diff options
Diffstat (limited to 'drivers')
1139 files changed, 48898 insertions, 45766 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1b3142127bf5..c07be024b962 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -97,7 +97,7 @@ obj-$(CONFIG_EISA) += eisa/ obj-y += lguest/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_IDLE) += cpuidle/ -obj-$(CONFIG_MMC) += mmc/ +obj-y += mmc/ obj-$(CONFIG_MEMSTICK) += memstick/ obj-y += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c index cb423f5aef24..c339a0880e6e 100644 --- a/drivers/accessibility/braille/braille_console.c +++ b/drivers/accessibility/braille/braille_console.c @@ -44,7 +44,7 @@ MODULE_LICENSE("GPL"); */ /* Emit various sounds */ -static int sound; +static bool sound; module_param(sound, bool, 0); MODULE_PARM_DESC(sound, "emit sounds"); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 76dc02f15574..e6652d716e45 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -108,7 +108,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); /* * Optionally enable output from the AML Debug Object. */ -u32 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); +bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE); /* * Optionally copy the entire DSDT to local memory (instead of simply diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index b8e08cb67a18..ebaf037a787b 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -118,7 +118,7 @@ struct ghes_estatus_cache { struct rcu_head rcu; }; -int ghes_disable; +bool ghes_disable; module_param_named(disable, ghes_disable, bool, 0); static int ghes_panic_timeout __read_mostly = 30; diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 05fee06f4d6e..ee7fddc4665c 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -41,7 +41,7 @@ #define HEST_PFX "HEST: " -int hest_disable; +bool hest_disable; EXPORT_SYMBOL_GPL(hest_disable); /* HEST table parsing */ diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 19a61136d848..88eb14304667 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -43,7 +43,7 @@ MODULE_AUTHOR("Kristen Carlson Accardi"); MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); -static int immediate_undock = 1; +static bool immediate_undock = 1; module_param(immediate_undock, bool, 0644); MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " "undock immediately when the undock button is pressed, 0 will cause" diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 07f7fea8a4e2..e50e31a518af 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -34,7 +34,7 @@ #include <acpi/acpi_drivers.h> #include <linux/dmi.h> -static int debug; +static bool debug; static int check_sta_before_sun; #define DRIVER_VERSION "0.1" diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 08a44b532f7c..eaef02afc7cf 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -69,21 +69,21 @@ MODULE_AUTHOR("Bruno Ducrot"); MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); -static int brightness_switch_enabled = 1; +static bool brightness_switch_enabled = 1; module_param(brightness_switch_enabled, bool, 0644); /* * By default, we don't allow duplicate ACPI video bus devices * under the same VGA controller */ -static int allow_duplicates; +static bool allow_duplicates; module_param(allow_duplicates, bool, 0644); /* * Some BIOSes claim they use minimum backlight at boot, * and this may bring dimming screen after boot */ -static int use_bios_initial_backlight = 1; +static bool use_bios_initial_backlight = 1; module_param(use_bios_initial_backlight, bool, 0644); static int register_count = 0; diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index e0bc9646a38e..55d6179dde58 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -599,9 +599,9 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, nv_pci_tbl); MODULE_VERSION(DRV_VERSION); -static int adma_enabled; -static int swncq_enabled = 1; -static int msi_enabled; +static bool adma_enabled; +static bool swncq_enabled = 1; +static bool msi_enabled; static void nv_adma_register_mode(struct ata_port *ap) { diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 1e9140626a83..e7e610aa9a7a 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -417,7 +417,7 @@ static struct ata_port_operations sil24_ops = { #endif }; -static int sata_sil24_msi; /* Disable MSI */ +static bool sata_sil24_msi; /* Disable MSI */ module_param_named(msi, sata_sil24_msi, bool, S_IRUGO); MODULE_PARM_DESC(msi, "Enable MSI (Default: false)"); diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 9a51df4f5b74..b182c2f7d777 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -112,12 +112,12 @@ static u8 read_prom_byte(struct he_dev *he_dev, int addr); /* globals */ static struct he_dev *he_devs; -static int disable64; +static bool disable64; static short nvpibits = -1; static short nvcibits = -1; static short rx_skb_reserve = 16; -static int irq_coalesce = 1; -static int sdh = 0; +static bool irq_coalesce = 1; +static bool sdh = 0; /* Read from EEPROM = 0000 0011b */ static unsigned int readtab[] = { diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index fcbec8ac134d..7be9f79018e9 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -179,7 +179,7 @@ config GENERIC_CPU_DEVICES source "drivers/base/regmap/Kconfig" config DMA_SHARED_BUFFER - bool "Buffer framework to be shared between drivers" + bool default n select ANON_INODES depends on EXPERIMENTAL diff --git a/drivers/base/memory.c b/drivers/base/memory.c index f17e3ea041c0..ed5de58c340f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -295,11 +295,22 @@ static int memory_block_change_state(struct memory_block *mem, ret = memory_block_action(mem->start_section_nr, to_state); - if (ret) + if (ret) { mem->state = from_state_req; - else - mem->state = to_state; + goto out; + } + mem->state = to_state; + switch (mem->state) { + case MEM_OFFLINE: + kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE); + break; + case MEM_ONLINE: + kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE); + break; + default: + break; + } out: mutex_unlock(&mem->state_mutex); return ret; diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 92e6a9048065..978bbf7ac6af 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1429,6 +1429,8 @@ static int pm_genpd_default_restore_state(struct device *dev) return 0; } +#ifdef CONFIG_PM_SLEEP + /** * pm_genpd_default_suspend - Default "device suspend" for PM domians. * @dev: Device to handle. @@ -1517,6 +1519,19 @@ static int pm_genpd_default_thaw(struct device *dev) return cb ? cb(dev) : pm_generic_thaw(dev); } +#else /* !CONFIG_PM_SLEEP */ + +#define pm_genpd_default_suspend NULL +#define pm_genpd_default_suspend_late NULL +#define pm_genpd_default_resume_early NULL +#define pm_genpd_default_resume NULL +#define pm_genpd_default_freeze NULL +#define pm_genpd_default_freeze_late NULL +#define pm_genpd_default_thaw_early NULL +#define pm_genpd_default_thaw NULL + +#endif /* !CONFIG_PM_SLEEP */ + /** * pm_genpd_init - Initialize a generic I/O PM domain object. * @genpd: PM domain object to initialize. diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 51527ee92d10..66a265bf5867 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -12,6 +12,8 @@ #include <linux/pm_qos.h> #include <linux/hrtimer.h> +#ifdef CONFIG_PM_RUNTIME + /** * default_stop_ok - Default PM domain governor routine for stopping devices. * @dev: Device to check. @@ -137,16 +139,28 @@ static bool default_power_down_ok(struct dev_pm_domain *pd) return true; } -struct dev_power_governor simple_qos_governor = { - .stop_ok = default_stop_ok, - .power_down_ok = default_power_down_ok, -}; - static bool always_on_power_down_ok(struct dev_pm_domain *domain) { return false; } +#else /* !CONFIG_PM_RUNTIME */ + +bool default_stop_ok(struct device *dev) +{ + return false; +} + +#define default_power_down_ok NULL +#define always_on_power_down_ok NULL + +#endif /* !CONFIG_PM_RUNTIME */ + +struct dev_power_governor simple_qos_governor = { + .stop_ok = default_stop_ok, + .power_down_ok = default_power_down_ok, +}; + /** * pm_genpd_gov_always_on - A governor implementing an always-on policy */ diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 6f07ec1c2f58..a30aa103f95b 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -116,6 +116,8 @@ config PARIDE source "drivers/block/paride/Kconfig" +source "drivers/block/mtip32xx/Kconfig" + config BLK_CPQ_DA tristate "Compaq SMART2 support" depends on PCI && VIRT_TO_BUS diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 76646e9a1c91..ad7b74a44ef3 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -39,5 +39,6 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/ obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ obj-$(CONFIG_BLK_DEV_RBD) += rbd.o +obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ swim_mod-y := swim.o swim_asm.o diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 587cce57adae..b0f553b26d0f 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1735,7 +1735,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, case CCISS_BIG_PASSTHRU: return cciss_bigpassthru(h, argp); - /* scsi_cmd_ioctl handles these, below, though some are not */ + /* scsi_cmd_blk_ioctl handles these, below, though some are not */ /* very meaningful for cciss. SG_IO is the main one people want. */ case SG_GET_VERSION_NUM: @@ -1746,9 +1746,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, case SG_EMULATED_HOST: case SG_IO: case SCSI_IOCTL_SEND_COMMAND: - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); + return scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); - /* scsi_cmd_ioctl would normally handle these, below, but */ + /* scsi_cmd_blk_ioctl would normally handle these, below, but */ /* they aren't a good fit for cciss, as CD-ROMs are */ /* not supported, and we don't have any bus/target/lun */ /* which we present to the kernel. */ diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9cf20355ceec..8d680562ba73 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -59,8 +59,8 @@ /* module parameter, defined in drbd_main.c */ extern unsigned int minor_count; -extern int disable_sendpage; -extern int allow_oos; +extern bool disable_sendpage; +extern bool allow_oos; extern unsigned int cn_idx; #ifdef CONFIG_DRBD_FAULT_INJECTION diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 0358e55356c8..211fc44f84be 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -117,8 +117,8 @@ module_param(fault_devs, int, 0644); /* module parameter, defined */ unsigned int minor_count = DRBD_MINOR_COUNT_DEF; -int disable_sendpage; -int allow_oos; +bool disable_sendpage; +bool allow_oos; unsigned int cn_idx = CN_IDX_DRBD; int proc_details; /* Detail level in proc drbd*/ diff --git a/drivers/block/mtip32xx/Kconfig b/drivers/block/mtip32xx/Kconfig new file mode 100644 index 000000000000..b5dd14e072f2 --- /dev/null +++ b/drivers/block/mtip32xx/Kconfig @@ -0,0 +1,9 @@ +# +# mtip32xx device driver configuration +# + +config BLK_DEV_PCIESSD_MTIP32XX + tristate "Block Device Driver for Micron PCIe SSDs" + depends on HOTPLUG_PCI_PCIE + help + This enables the block driver for Micron PCIe SSDs. diff --git a/drivers/block/mtip32xx/Makefile b/drivers/block/mtip32xx/Makefile new file mode 100644 index 000000000000..4fbef8c8329b --- /dev/null +++ b/drivers/block/mtip32xx/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Block device driver for Micron PCIe SSD +# + +obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx.o diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c new file mode 100644 index 000000000000..b74eab70c3d0 --- /dev/null +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -0,0 +1,3651 @@ +/* + * Driver for the Micron P320 SSD + * Copyright (C) 2011 Micron Technology, Inc. + * + * Portions of this code were derived from works subjected to the + * following copyright: + * Copyright (C) 2009 Integrated Device Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/ata.h> +#include <linux/delay.h> +#include <linux/hdreg.h> +#include <linux/uaccess.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/compat.h> +#include <linux/fs.h> +#include <linux/module.h> +#include <linux/genhd.h> +#include <linux/blkdev.h> +#include <linux/bio.h> +#include <linux/dma-mapping.h> +#include <linux/idr.h> +#include <linux/kthread.h> +#include <../drivers/ata/ahci.h> +#include "mtip32xx.h" + +#define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32) +#define HW_CMD_TBL_SZ (AHCI_CMD_TBL_HDR_SZ + (MTIP_MAX_SG * 16)) +#define HW_CMD_TBL_AR_SZ (HW_CMD_TBL_SZ * MTIP_MAX_COMMAND_SLOTS) +#define HW_PORT_PRIV_DMA_SZ \ + (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ) + +#define HOST_HSORG 0xFC +#define HSORG_DISABLE_SLOTGRP_INTR (1<<24) +#define HSORG_DISABLE_SLOTGRP_PXIS (1<<16) +#define HSORG_HWREV 0xFF00 +#define HSORG_STYLE 0x8 +#define HSORG_SLOTGROUPS 0x7 + +#define PORT_COMMAND_ISSUE 0x38 +#define PORT_SDBV 0x7C + +#define PORT_OFFSET 0x100 +#define PORT_MEM_SIZE 0x80 + +#define PORT_IRQ_ERR \ + (PORT_IRQ_HBUS_ERR | PORT_IRQ_IF_ERR | PORT_IRQ_CONNECT | \ + PORT_IRQ_PHYRDY | PORT_IRQ_UNK_FIS | PORT_IRQ_BAD_PMP | \ + PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_DATA_ERR | PORT_IRQ_IF_NONFATAL | \ + PORT_IRQ_OVERFLOW) +#define PORT_IRQ_LEGACY \ + (PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS) +#define PORT_IRQ_HANDLED \ + (PORT_IRQ_SDB_FIS | PORT_IRQ_LEGACY | \ + PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR | \ + PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY) +#define DEF_PORT_IRQ \ + (PORT_IRQ_ERR | PORT_IRQ_LEGACY | PORT_IRQ_SDB_FIS) + +/* product numbers */ +#define MTIP_PRODUCT_UNKNOWN 0x00 +#define MTIP_PRODUCT_ASICFPGA 0x11 + +/* Device instance number, incremented each time a device is probed. */ +static int instance; + +/* + * Global variable used to hold the major block device number + * allocated in mtip_init(). + */ +static int mtip_major; + +static DEFINE_SPINLOCK(rssd_index_lock); +static DEFINE_IDA(rssd_index_ida); + +static int mtip_block_initialize(struct driver_data *dd); + +#ifdef CONFIG_COMPAT +struct mtip_compat_ide_task_request_s { + __u8 io_ports[8]; + __u8 hob_ports[8]; + ide_reg_valid_t out_flags; + ide_reg_valid_t in_flags; + int data_phase; + int req_cmd; + compat_ulong_t out_size; + compat_ulong_t in_size; +}; +#endif + +/* + * This function check_for_surprise_removal is called + * while card is removed from the system and it will + * read the vendor id from the configration space + * + * @pdev Pointer to the pci_dev structure. + * + * return value + * true if device removed, else false + */ +static bool mtip_check_surprise_removal(struct pci_dev *pdev) +{ + u16 vendor_id = 0; + + /* Read the vendorID from the configuration space */ + pci_read_config_word(pdev, 0x00, &vendor_id); + if (vendor_id == 0xFFFF) + return true; /* device removed */ + + return false; /* device present */ +} + +/* + * This function is called for clean the pending command in the + * command slot during the surprise removal of device and return + * error to the upper layer. + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * None + */ +static void mtip_command_cleanup(struct driver_data *dd) +{ + int group = 0, commandslot = 0, commandindex = 0; + struct mtip_cmd *command; + struct mtip_port *port = dd->port; + + for (group = 0; group < 4; group++) { + for (commandslot = 0; commandslot < 32; commandslot++) { + if (!(port->allocated[group] & (1 << commandslot))) + continue; + + commandindex = group << 5 | commandslot; + command = &port->commands[commandindex]; + + if (atomic_read(&command->active) + && (command->async_callback)) { + command->async_callback(command->async_data, + -ENODEV); + command->async_callback = NULL; + command->async_data = NULL; + } + + dma_unmap_sg(&port->dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + } + } + + up(&port->cmd_slot); + + atomic_set(&dd->drv_cleanup_done, true); +} + +/* + * Obtain an empty command slot. + * + * This function needs to be reentrant since it could be called + * at the same time on multiple CPUs. The allocation of the + * command slot must be atomic. + * + * @port Pointer to the port data structure. + * + * return value + * >= 0 Index of command slot obtained. + * -1 No command slots available. + */ +static int get_slot(struct mtip_port *port) +{ + int slot, i; + unsigned int num_command_slots = port->dd->slot_groups * 32; + + /* + * Try 10 times, because there is a small race here. + * that's ok, because it's still cheaper than a lock. + * + * Race: Since this section is not protected by lock, same bit + * could be chosen by different process contexts running in + * different processor. So instead of costly lock, we are going + * with loop. + */ + for (i = 0; i < 10; i++) { + slot = find_next_zero_bit(port->allocated, + num_command_slots, 1); + if ((slot < num_command_slots) && + (!test_and_set_bit(slot, port->allocated))) + return slot; + } + dev_warn(&port->dd->pdev->dev, "Failed to get a tag.\n"); + + if (mtip_check_surprise_removal(port->dd->pdev)) { + /* Device not present, clean outstanding commands */ + mtip_command_cleanup(port->dd); + } + return -1; +} + +/* + * Release a command slot. + * + * @port Pointer to the port data structure. + * @tag Tag of command to release + * + * return value + * None + */ +static inline void release_slot(struct mtip_port *port, int tag) +{ + smp_mb__before_clear_bit(); + clear_bit(tag, port->allocated); + smp_mb__after_clear_bit(); +} + +/* + * Reset the HBA (without sleeping) + * + * Just like hba_reset, except does not call sleep, so can be + * run from interrupt/tasklet context. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 The reset was successful. + * -1 The HBA Reset bit did not clear. + */ +static int hba_reset_nosleep(struct driver_data *dd) +{ + unsigned long timeout; + + /* Chip quirk: quiesce any chip function */ + mdelay(10); + + /* Set the reset bit */ + writel(HOST_RESET, dd->mmio + HOST_CTL); + + /* Flush */ + readl(dd->mmio + HOST_CTL); + + /* + * Wait 10ms then spin for up to 1 second + * waiting for reset acknowledgement + */ + timeout = jiffies + msecs_to_jiffies(1000); + mdelay(10); + while ((readl(dd->mmio + HOST_CTL) & HOST_RESET) + && time_before(jiffies, timeout)) + mdelay(1); + + if (readl(dd->mmio + HOST_CTL) & HOST_RESET) + return -1; + + return 0; +} + +/* + * Issue a command to the hardware. + * + * Set the appropriate bit in the s_active and Command Issue hardware + * registers, causing hardware command processing to begin. + * + * @port Pointer to the port structure. + * @tag The tag of the command to be issued. + * + * return value + * None + */ +static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) +{ + unsigned long flags = 0; + + atomic_set(&port->commands[tag].active, 1); + + spin_lock_irqsave(&port->cmd_issue_lock, flags); + + writel((1 << MTIP_TAG_BIT(tag)), + port->s_active[MTIP_TAG_INDEX(tag)]); + writel((1 << MTIP_TAG_BIT(tag)), + port->cmd_issue[MTIP_TAG_INDEX(tag)]); + + spin_unlock_irqrestore(&port->cmd_issue_lock, flags); +} + +/* + * Enable/disable the reception of FIS + * + * @port Pointer to the port data structure + * @enable 1 to enable, 0 to disable + * + * return value + * Previous state: 1 enabled, 0 disabled + */ +static int mtip_enable_fis(struct mtip_port *port, int enable) +{ + u32 tmp; + + /* enable FIS reception */ + tmp = readl(port->mmio + PORT_CMD); + if (enable) + writel(tmp | PORT_CMD_FIS_RX, port->mmio + PORT_CMD); + else + writel(tmp & ~PORT_CMD_FIS_RX, port->mmio + PORT_CMD); + + /* Flush */ + readl(port->mmio + PORT_CMD); + + return (((tmp & PORT_CMD_FIS_RX) == PORT_CMD_FIS_RX)); +} + +/* + * Enable/disable the DMA engine + * + * @port Pointer to the port data structure + * @enable 1 to enable, 0 to disable + * + * return value + * Previous state: 1 enabled, 0 disabled. + */ +static int mtip_enable_engine(struct mtip_port *port, int enable) +{ + u32 tmp; + + /* enable FIS reception */ + tmp = readl(port->mmio + PORT_CMD); + if (enable) + writel(tmp | PORT_CMD_START, port->mmio + PORT_CMD); + else + writel(tmp & ~PORT_CMD_START, port->mmio + PORT_CMD); + + readl(port->mmio + PORT_CMD); + return (((tmp & PORT_CMD_START) == PORT_CMD_START)); +} + +/* + * Enables the port DMA engine and FIS reception. + * + * return value + * None + */ +static inline void mtip_start_port(struct mtip_port *port) +{ + /* Enable FIS reception */ + mtip_enable_fis(port, 1); + + /* Enable the DMA engine */ + mtip_enable_engine(port, 1); +} + +/* + * Deinitialize a port by disabling port interrupts, the DMA engine, + * and FIS reception. + * + * @port Pointer to the port structure + * + * return value + * None + */ +static inline void mtip_deinit_port(struct mtip_port *port) +{ + /* Disable interrupts on this port */ + writel(0, port->mmio + PORT_IRQ_MASK); + + /* Disable the DMA engine */ + mtip_enable_engine(port, 0); + + /* Disable FIS reception */ + mtip_enable_fis(port, 0); +} + +/* + * Initialize a port. + * + * This function deinitializes the port by calling mtip_deinit_port() and + * then initializes it by setting the command header and RX FIS addresses, + * clearing the SError register and any pending port interrupts before + * re-enabling the default set of port interrupts. + * + * @port Pointer to the port structure. + * + * return value + * None + */ +static void mtip_init_port(struct mtip_port *port) +{ + int i; + mtip_deinit_port(port); + + /* Program the command list base and FIS base addresses */ + if (readl(port->dd->mmio + HOST_CAP) & HOST_CAP_64) { + writel((port->command_list_dma >> 16) >> 16, + port->mmio + PORT_LST_ADDR_HI); + writel((port->rxfis_dma >> 16) >> 16, + port->mmio + PORT_FIS_ADDR_HI); + } + + writel(port->command_list_dma & 0xFFFFFFFF, + port->mmio + PORT_LST_ADDR); + writel(port->rxfis_dma & 0xFFFFFFFF, port->mmio + PORT_FIS_ADDR); + + /* Clear SError */ + writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR); + + /* reset the completed registers.*/ + for (i = 0; i < port->dd->slot_groups; i++) + writel(0xFFFFFFFF, port->completed[i]); + + /* Clear any pending interrupts for this port */ + writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + + /* Enable port interrupts */ + writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK); +} + +/* + * Restart a port + * + * @port Pointer to the port data structure. + * + * return value + * None + */ +static void mtip_restart_port(struct mtip_port *port) +{ + unsigned long timeout; + + /* Disable the DMA engine */ + mtip_enable_engine(port, 0); + + /* Chip quirk: wait up to 500ms for PxCMD.CR == 0 */ + timeout = jiffies + msecs_to_jiffies(500); + while ((readl(port->mmio + PORT_CMD) & PORT_CMD_LIST_ON) + && time_before(jiffies, timeout)) + ; + + /* + * Chip quirk: escalate to hba reset if + * PxCMD.CR not clear after 500 ms + */ + if (readl(port->mmio + PORT_CMD) & PORT_CMD_LIST_ON) { + dev_warn(&port->dd->pdev->dev, + "PxCMD.CR not clear, escalating reset\n"); + + if (hba_reset_nosleep(port->dd)) + dev_err(&port->dd->pdev->dev, + "HBA reset escalation failed.\n"); + + /* 30 ms delay before com reset to quiesce chip */ + mdelay(30); + } + + dev_warn(&port->dd->pdev->dev, "Issuing COM reset\n"); + + /* Set PxSCTL.DET */ + writel(readl(port->mmio + PORT_SCR_CTL) | + 1, port->mmio + PORT_SCR_CTL); + readl(port->mmio + PORT_SCR_CTL); + + /* Wait 1 ms to quiesce chip function */ + timeout = jiffies + msecs_to_jiffies(1); + while (time_before(jiffies, timeout)) + ; + + /* Clear PxSCTL.DET */ + writel(readl(port->mmio + PORT_SCR_CTL) & ~1, + port->mmio + PORT_SCR_CTL); + readl(port->mmio + PORT_SCR_CTL); + + /* Wait 500 ms for bit 0 of PORT_SCR_STS to be set */ + timeout = jiffies + msecs_to_jiffies(500); + while (((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) + && time_before(jiffies, timeout)) + ; + + if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) + dev_warn(&port->dd->pdev->dev, + "COM reset failed\n"); + + /* Clear SError, the PxSERR.DIAG.x should be set so clear it */ + writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR); + + /* Enable the DMA engine */ + mtip_enable_engine(port, 1); +} + +/* + * Called periodically to see if any read/write commands are + * taking too long to complete. + * + * @data Pointer to the PORT data structure. + * + * return value + * None + */ +static void mtip_timeout_function(unsigned long int data) +{ + struct mtip_port *port = (struct mtip_port *) data; + struct host_to_dev_fis *fis; + struct mtip_cmd *command; + int tag, cmdto_cnt = 0; + unsigned int bit, group; + unsigned int num_command_slots = port->dd->slot_groups * 32; + + if (unlikely(!port)) + return; + + if (atomic_read(&port->dd->resumeflag) == true) { + mod_timer(&port->cmd_timer, + jiffies + msecs_to_jiffies(30000)); + return; + } + + for (tag = 0; tag < num_command_slots; tag++) { + /* + * Skip internal command slot as it has + * its own timeout mechanism + */ + if (tag == MTIP_TAG_INTERNAL) + continue; + + if (atomic_read(&port->commands[tag].active) && + (time_after(jiffies, port->commands[tag].comp_time))) { + group = tag >> 5; + bit = tag & 0x1F; + + command = &port->commands[tag]; + fis = (struct host_to_dev_fis *) command->command; + + dev_warn(&port->dd->pdev->dev, + "Timeout for command tag %d\n", tag); + + cmdto_cnt++; + if (cmdto_cnt == 1) + set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + + /* + * Clear the completed bit. This should prevent + * any interrupt handlers from trying to retire + * the command. + */ + writel(1 << bit, port->completed[group]); + + /* Call the async completion callback. */ + if (likely(command->async_callback)) + command->async_callback(command->async_data, + -EIO); + command->async_callback = NULL; + command->comp_func = NULL; + + /* Unmap the DMA scatter list entries */ + dma_unmap_sg(&port->dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + + /* + * Clear the allocated bit and active tag for the + * command. + */ + atomic_set(&port->commands[tag].active, 0); + release_slot(port, tag); + + up(&port->cmd_slot); + } + } + + if (cmdto_cnt) { + dev_warn(&port->dd->pdev->dev, + "%d commands timed out: restarting port", + cmdto_cnt); + mtip_restart_port(port); + clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + } + + /* Restart the timer */ + mod_timer(&port->cmd_timer, + jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); +} + +/* + * IO completion function. + * + * This completion function is called by the driver ISR when a + * command that was issued by the kernel completes. It first calls the + * asynchronous completion function which normally calls back into the block + * layer passing the asynchronous callback data, then unmaps the + * scatter list associated with the completed command, and finally + * clears the allocated bit associated with the completed command. + * + * @port Pointer to the port data structure. + * @tag Tag of the command. + * @data Pointer to driver_data. + * @status Completion status. + * + * return value + * None + */ +static void mtip_async_complete(struct mtip_port *port, + int tag, + void *data, + int status) +{ + struct mtip_cmd *command; + struct driver_data *dd = data; + int cb_status = status ? -EIO : 0; + + if (unlikely(!dd) || unlikely(!port)) + return; + + command = &port->commands[tag]; + + if (unlikely(status == PORT_IRQ_TF_ERR)) { + dev_warn(&port->dd->pdev->dev, + "Command tag %d failed due to TFE\n", tag); + } + + /* Upper layer callback */ + if (likely(command->async_callback)) + command->async_callback(command->async_data, cb_status); + + command->async_callback = NULL; + command->comp_func = NULL; + + /* Unmap the DMA scatter list entries */ + dma_unmap_sg(&dd->pdev->dev, + command->sg, + command->scatter_ents, + command->direction); + + /* Clear the allocated and active bits for the command */ + atomic_set(&port->commands[tag].active, 0); + release_slot(port, tag); + + up(&port->cmd_slot); +} + +/* + * Internal command completion callback function. + * + * This function is normally called by the driver ISR when an internal + * command completed. This function signals the command completion by + * calling complete(). + * + * @port Pointer to the port data structure. + * @tag Tag of the command that has completed. + * @data Pointer to a completion structure. + * @status Completion status. + * + * return value + * None + */ +static void mtip_completion(struct mtip_port *port, + int tag, + void *data, + int status) +{ + struct mtip_cmd *command = &port->commands[tag]; + struct completion *waiting = data; + if (unlikely(status == PORT_IRQ_TF_ERR)) + dev_warn(&port->dd->pdev->dev, + "Internal command %d completed with TFE\n", tag); + + command->async_callback = NULL; + command->comp_func = NULL; + + complete(waiting); +} + +/* + * Helper function for tag logging + */ +static void print_tags(struct driver_data *dd, + char *msg, + unsigned long *tagbits) +{ + unsigned int tag, count = 0; + + for (tag = 0; tag < (dd->slot_groups) * 32; tag++) { + if (test_bit(tag, tagbits)) + count++; + } + if (count) + dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); +} + +/* + * Handle an error. + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * None + */ +static void mtip_handle_tfe(struct driver_data *dd) +{ + int group, tag, bit, reissue; + struct mtip_port *port; + struct mtip_cmd *command; + u32 completed; + struct host_to_dev_fis *fis; + unsigned long tagaccum[SLOTBITS_IN_LONGS]; + + dev_warn(&dd->pdev->dev, "Taskfile error\n"); + + port = dd->port; + + /* Stop the timer to prevent command timeouts. */ + del_timer(&port->cmd_timer); + + /* Set eh_active */ + set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + + /* Loop through all the groups */ + for (group = 0; group < dd->slot_groups; group++) { + completed = readl(port->completed[group]); + + /* clear completed status register in the hardware.*/ + writel(completed, port->completed[group]); + + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + + /* Process successfully completed commands */ + for (bit = 0; bit < 32 && completed; bit++) { + if (!(completed & (1<<bit))) + continue; + tag = (group << 5) + bit; + + /* Skip the internal command slot */ + if (tag == MTIP_TAG_INTERNAL) + continue; + + command = &port->commands[tag]; + if (likely(command->comp_func)) { + set_bit(tag, tagaccum); + atomic_set(&port->commands[tag].active, 0); + command->comp_func(port, + tag, + command->comp_data, + 0); + } else { + dev_err(&port->dd->pdev->dev, + "Missing completion func for tag %d", + tag); + if (mtip_check_surprise_removal(dd->pdev)) { + mtip_command_cleanup(dd); + /* don't proceed further */ + return; + } + } + } + } + print_tags(dd, "TFE tags completed:", tagaccum); + + /* Restart the port */ + mdelay(20); + mtip_restart_port(port); + + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + + /* Loop through all the groups */ + for (group = 0; group < dd->slot_groups; group++) { + for (bit = 0; bit < 32; bit++) { + reissue = 1; + tag = (group << 5) + bit; + + /* If the active bit is set re-issue the command */ + if (atomic_read(&port->commands[tag].active) == 0) + continue; + + fis = (struct host_to_dev_fis *) + port->commands[tag].command; + + /* Should re-issue? */ + if (tag == MTIP_TAG_INTERNAL || + fis->command == ATA_CMD_SET_FEATURES) + reissue = 0; + + /* + * First check if this command has + * exceeded its retries. + */ + if (reissue && + (port->commands[tag].retries-- > 0)) { + + set_bit(tag, tagaccum); + + /* Update the timeout value. */ + port->commands[tag].comp_time = + jiffies + msecs_to_jiffies( + MTIP_NCQ_COMMAND_TIMEOUT_MS); + /* Re-issue the command. */ + mtip_issue_ncq_command(port, tag); + + continue; + } + + /* Retire a command that will not be reissued */ + dev_warn(&port->dd->pdev->dev, + "retiring tag %d\n", tag); + atomic_set(&port->commands[tag].active, 0); + + if (port->commands[tag].comp_func) + port->commands[tag].comp_func( + port, + tag, + port->commands[tag].comp_data, + PORT_IRQ_TF_ERR); + else + dev_warn(&port->dd->pdev->dev, + "Bad completion for tag %d\n", + tag); + } + } + print_tags(dd, "TFE tags reissued:", tagaccum); + + /* clear eh_active */ + clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + + mod_timer(&port->cmd_timer, + jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); +} + +/* + * Handle a set device bits interrupt + */ +static inline void mtip_process_sdbf(struct driver_data *dd) +{ + struct mtip_port *port = dd->port; + int group, tag, bit; + u32 completed; + struct mtip_cmd *command; + + /* walk all bits in all slot groups */ + for (group = 0; group < dd->slot_groups; group++) { + completed = readl(port->completed[group]); + + /* clear completed status register in the hardware.*/ + writel(completed, port->completed[group]); + + /* Process completed commands. */ + for (bit = 0; + (bit < 32) && completed; + bit++, completed >>= 1) { + if (completed & 0x01) { + tag = (group << 5) | bit; + + /* skip internal command slot. */ + if (unlikely(tag == MTIP_TAG_INTERNAL)) + continue; + + command = &port->commands[tag]; + /* make internal callback */ + if (likely(command->comp_func)) { + command->comp_func( + port, + tag, + command->comp_data, + 0); + } else { + dev_warn(&dd->pdev->dev, + "Null completion " + "for tag %d", + tag); + + if (mtip_check_surprise_removal( + dd->pdev)) { + mtip_command_cleanup(dd); + return; + } + } + } + } + } +} + +/* + * Process legacy pio and d2h interrupts + */ +static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) +{ + struct mtip_port *port = dd->port; + struct mtip_cmd *cmd = &port->commands[MTIP_TAG_INTERNAL]; + + if (test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && + (cmd != NULL) && !(readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL))) { + if (cmd->comp_func) { + cmd->comp_func(port, + MTIP_TAG_INTERNAL, + cmd->comp_data, + 0); + return; + } + } + + dev_warn(&dd->pdev->dev, "IRQ status 0x%x ignored.\n", port_stat); + + return; +} + +/* + * Demux and handle errors + */ +static inline void mtip_process_errors(struct driver_data *dd, u32 port_stat) +{ + if (likely(port_stat & (PORT_IRQ_TF_ERR | PORT_IRQ_IF_ERR))) + mtip_handle_tfe(dd); + + if (unlikely(port_stat & PORT_IRQ_CONNECT)) { + dev_warn(&dd->pdev->dev, + "Clearing PxSERR.DIAG.x\n"); + writel((1 << 26), dd->port->mmio + PORT_SCR_ERR); + } + + if (unlikely(port_stat & PORT_IRQ_PHYRDY)) { + dev_warn(&dd->pdev->dev, + "Clearing PxSERR.DIAG.n\n"); + writel((1 << 16), dd->port->mmio + PORT_SCR_ERR); + } + + if (unlikely(port_stat & ~PORT_IRQ_HANDLED)) { + dev_warn(&dd->pdev->dev, + "Port stat errors %x unhandled\n", + (port_stat & ~PORT_IRQ_HANDLED)); + } +} + +static inline irqreturn_t mtip_handle_irq(struct driver_data *data) +{ + struct driver_data *dd = (struct driver_data *) data; + struct mtip_port *port = dd->port; + u32 hba_stat, port_stat; + int rv = IRQ_NONE; + + hba_stat = readl(dd->mmio + HOST_IRQ_STAT); + if (hba_stat) { + rv = IRQ_HANDLED; + + /* Acknowledge the interrupt status on the port.*/ + port_stat = readl(port->mmio + PORT_IRQ_STAT); + writel(port_stat, port->mmio + PORT_IRQ_STAT); + + /* Demux port status */ + if (likely(port_stat & PORT_IRQ_SDB_FIS)) + mtip_process_sdbf(dd); + + if (unlikely(port_stat & PORT_IRQ_ERR)) { + if (unlikely(mtip_check_surprise_removal(dd->pdev))) { + mtip_command_cleanup(dd); + /* don't proceed further */ + return IRQ_HANDLED; + } + + mtip_process_errors(dd, port_stat & PORT_IRQ_ERR); + } + + if (unlikely(port_stat & PORT_IRQ_LEGACY)) + mtip_process_legacy(dd, port_stat & PORT_IRQ_LEGACY); + } + + /* acknowledge interrupt */ + writel(hba_stat, dd->mmio + HOST_IRQ_STAT); + + return rv; +} + +/* + * Wrapper for mtip_handle_irq + * (ignores return code) + */ +static void mtip_tasklet(unsigned long data) +{ + mtip_handle_irq((struct driver_data *) data); +} + +/* + * HBA interrupt subroutine. + * + * @irq IRQ number. + * @instance Pointer to the driver data structure. + * + * return value + * IRQ_HANDLED A HBA interrupt was pending and handled. + * IRQ_NONE This interrupt was not for the HBA. + */ +static irqreturn_t mtip_irq_handler(int irq, void *instance) +{ + struct driver_data *dd = instance; + tasklet_schedule(&dd->tasklet); + return IRQ_HANDLED; +} + +static void mtip_issue_non_ncq_command(struct mtip_port *port, int tag) +{ + atomic_set(&port->commands[tag].active, 1); + writel(1 << MTIP_TAG_BIT(tag), + port->cmd_issue[MTIP_TAG_INDEX(tag)]); +} + +/* + * Wait for port to quiesce + * + * @port Pointer to port data structure + * @timeout Max duration to wait (ms) + * + * return value + * 0 Success + * -EBUSY Commands still active + */ +static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) +{ + unsigned long to; + unsigned int n; + unsigned int active = 1; + + to = jiffies + msecs_to_jiffies(timeout); + do { + if (test_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags) && + test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + msleep(20); + continue; /* svc thd is actively issuing commands */ + } + /* + * Ignore s_active bit 0 of array element 0. + * This bit will always be set + */ + active = readl(port->s_active[0]) & 0xFFFFFFFE; + for (n = 1; n < port->dd->slot_groups; n++) + active |= readl(port->s_active[n]); + + if (!active) + break; + + msleep(20); + } while (time_before(jiffies, to)); + + return active ? -EBUSY : 0; +} + +/* + * Execute an internal command and wait for the completion. + * + * @port Pointer to the port data structure. + * @fis Pointer to the FIS that describes the command. + * @fis_len Length in WORDS of the FIS. + * @buffer DMA accessible for command data. + * @buf_len Length, in bytes, of the data buffer. + * @opts Command header options, excluding the FIS length + * and the number of PRD entries. + * @timeout Time in ms to wait for the command to complete. + * + * return value + * 0 Command completed successfully. + * -EFAULT The buffer address is not correctly aligned. + * -EBUSY Internal command or other IO in progress. + * -EAGAIN Time out waiting for command to complete. + */ +static int mtip_exec_internal_command(struct mtip_port *port, + void *fis, + int fis_len, + dma_addr_t buffer, + int buf_len, + u32 opts, + gfp_t atomic, + unsigned long timeout) +{ + struct mtip_cmd_sg *command_sg; + DECLARE_COMPLETION_ONSTACK(wait); + int rv = 0; + struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL]; + + /* Make sure the buffer is 8 byte aligned. This is asic specific. */ + if (buffer & 0x00000007) { + dev_err(&port->dd->pdev->dev, + "SG buffer is not 8 byte aligned\n"); + return -EFAULT; + } + + /* Only one internal command should be running at a time */ + if (test_and_set_bit(MTIP_TAG_INTERNAL, port->allocated)) { + dev_warn(&port->dd->pdev->dev, + "Internal command already active\n"); + return -EBUSY; + } + set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + + if (atomic == GFP_KERNEL) { + /* wait for io to complete if non atomic */ + if (mtip_quiesce_io(port, 5000) < 0) { + dev_warn(&port->dd->pdev->dev, + "Failed to quiesce IO\n"); + release_slot(port, MTIP_TAG_INTERNAL); + clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + return -EBUSY; + } + + /* Set the completion function and data for the command. */ + int_cmd->comp_data = &wait; + int_cmd->comp_func = mtip_completion; + + } else { + /* Clear completion - we're going to poll */ + int_cmd->comp_data = NULL; + int_cmd->comp_func = NULL; + } + + /* Copy the command to the command table */ + memcpy(int_cmd->command, fis, fis_len*4); + + /* Populate the SG list */ + int_cmd->command_header->opts = + __force_bit2int cpu_to_le32(opts | fis_len); + if (buf_len) { + command_sg = int_cmd->command + AHCI_CMD_TBL_HDR_SZ; + + command_sg->info = + __force_bit2int cpu_to_le32((buf_len-1) & 0x3FFFFF); + command_sg->dba = + __force_bit2int cpu_to_le32(buffer & 0xFFFFFFFF); + command_sg->dba_upper = + __force_bit2int cpu_to_le32((buffer >> 16) >> 16); + + int_cmd->command_header->opts |= + __force_bit2int cpu_to_le32((1 << 16)); + } + + /* Populate the command header */ + int_cmd->command_header->byte_count = 0; + + /* Issue the command to the hardware */ + mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL); + + /* Poll if atomic, wait_for_completion otherwise */ + if (atomic == GFP_KERNEL) { + /* Wait for the command to complete or timeout. */ + if (wait_for_completion_timeout( + &wait, + msecs_to_jiffies(timeout)) == 0) { + dev_err(&port->dd->pdev->dev, + "Internal command did not complete [%d] " + "within timeout of %lu ms\n", + atomic, timeout); + rv = -EAGAIN; + } + + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) { + dev_warn(&port->dd->pdev->dev, + "Retiring internal command but CI is 1.\n"); + } + + } else { + /* Spin for <timeout> checking if command still outstanding */ + timeout = jiffies + msecs_to_jiffies(timeout); + + while ((readl( + port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) + && time_before(jiffies, timeout)) + ; + + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) { + dev_err(&port->dd->pdev->dev, + "Internal command did not complete [%d]\n", + atomic); + rv = -EAGAIN; + } + } + + /* Clear the allocated and active bits for the internal command. */ + atomic_set(&int_cmd->active, 0); + release_slot(port, MTIP_TAG_INTERNAL); + clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + + return rv; +} + +/* + * Byte-swap ATA ID strings. + * + * ATA identify data contains strings in byte-swapped 16-bit words. + * They must be swapped (on all architectures) to be usable as C strings. + * This function swaps bytes in-place. + * + * @buf The buffer location of the string + * @len The number of bytes to swap + * + * return value + * None + */ +static inline void ata_swap_string(u16 *buf, unsigned int len) +{ + int i; + for (i = 0; i < (len/2); i++) + be16_to_cpus(&buf[i]); +} + +/* + * Request the device identity information. + * + * If a user space buffer is not specified, i.e. is NULL, the + * identify information is still read from the drive and placed + * into the identify data buffer (@e port->identify) in the + * port data structure. + * When the identify buffer contains valid identify information @e + * port->identify_valid is non-zero. + * + * @port Pointer to the port structure. + * @user_buffer A user space buffer where the identify data should be + * copied. + * + * return value + * 0 Command completed successfully. + * -EFAULT An error occurred while coping data to the user buffer. + * -1 Command failed. + */ +static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) +{ + int rv = 0; + struct host_to_dev_fis fis; + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_ID_ATA; + + /* Set the identify information as invalid. */ + port->identify_valid = 0; + + /* Clear the identify information. */ + memset(port->identify, 0, sizeof(u16) * ATA_ID_WORDS); + + /* Execute the command. */ + if (mtip_exec_internal_command(port, + &fis, + 5, + port->identify_dma, + sizeof(u16) * ATA_ID_WORDS, + 0, + GFP_KERNEL, + MTIP_INTERNAL_COMMAND_TIMEOUT_MS) + < 0) { + rv = -1; + goto out; + } + + /* + * Perform any necessary byte-swapping. Yes, the kernel does in fact + * perform field-sensitive swapping on the string fields. + * See the kernel use of ata_id_string() for proof of this. + */ +#ifdef __LITTLE_ENDIAN + ata_swap_string(port->identify + 27, 40); /* model string*/ + ata_swap_string(port->identify + 23, 8); /* firmware string*/ + ata_swap_string(port->identify + 10, 20); /* serial# string*/ +#else + { + int i; + for (i = 0; i < ATA_ID_WORDS; i++) + port->identify[i] = le16_to_cpu(port->identify[i]); + } +#endif + + /* Set the identify buffer as valid. */ + port->identify_valid = 1; + + if (user_buffer) { + if (copy_to_user( + user_buffer, + port->identify, + ATA_ID_WORDS * sizeof(u16))) { + rv = -EFAULT; + goto out; + } + } + +out: + return rv; +} + +/* + * Issue a standby immediate command to the device. + * + * @port Pointer to the port structure. + * + * return value + * 0 Command was executed successfully. + * -1 An error occurred while executing the command. + */ +static int mtip_standby_immediate(struct mtip_port *port) +{ + int rv; + struct host_to_dev_fis fis; + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_STANDBYNOW1; + + /* Execute the command. Use a 15-second timeout for large drives. */ + rv = mtip_exec_internal_command(port, + &fis, + 5, + 0, + 0, + 0, + GFP_KERNEL, + 15000); + + return rv; +} + +/* + * Get the drive capacity. + * + * @dd Pointer to the device data structure. + * @sectors Pointer to the variable that will receive the sector count. + * + * return value + * 1 Capacity was returned successfully. + * 0 The identify information is invalid. + */ +static bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors) +{ + struct mtip_port *port = dd->port; + u64 total, raw0, raw1, raw2, raw3; + raw0 = port->identify[100]; + raw1 = port->identify[101]; + raw2 = port->identify[102]; + raw3 = port->identify[103]; + total = raw0 | raw1<<16 | raw2<<32 | raw3<<48; + *sectors = total; + return (bool) !!port->identify_valid; +} + +/* + * Reset the HBA. + * + * Resets the HBA by setting the HBA Reset bit in the Global + * HBA Control register. After setting the HBA Reset bit the + * function waits for 1 second before reading the HBA Reset + * bit to make sure it has cleared. If HBA Reset is not clear + * an error is returned. Cannot be used in non-blockable + * context. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 The reset was successful. + * -1 The HBA Reset bit did not clear. + */ +static int mtip_hba_reset(struct driver_data *dd) +{ + mtip_deinit_port(dd->port); + + /* Set the reset bit */ + writel(HOST_RESET, dd->mmio + HOST_CTL); + + /* Flush */ + readl(dd->mmio + HOST_CTL); + + /* Wait for reset to clear */ + ssleep(1); + + /* Check the bit has cleared */ + if (readl(dd->mmio + HOST_CTL) & HOST_RESET) { + dev_err(&dd->pdev->dev, + "Reset bit did not clear.\n"); + return -1; + } + + return 0; +} + +/* + * Display the identify command data. + * + * @port Pointer to the port data structure. + * + * return value + * None + */ +static void mtip_dump_identify(struct mtip_port *port) +{ + sector_t sectors; + unsigned short revid; + char cbuf[42]; + + if (!port->identify_valid) + return; + + strlcpy(cbuf, (char *)(port->identify+10), 21); + dev_info(&port->dd->pdev->dev, + "Serial No.: %s\n", cbuf); + + strlcpy(cbuf, (char *)(port->identify+23), 9); + dev_info(&port->dd->pdev->dev, + "Firmware Ver.: %s\n", cbuf); + + strlcpy(cbuf, (char *)(port->identify+27), 41); + dev_info(&port->dd->pdev->dev, "Model: %s\n", cbuf); + + if (mtip_hw_get_capacity(port->dd, §ors)) + dev_info(&port->dd->pdev->dev, + "Capacity: %llu sectors (%llu MB)\n", + (u64)sectors, + ((u64)sectors) * ATA_SECT_SIZE >> 20); + + pci_read_config_word(port->dd->pdev, PCI_REVISION_ID, &revid); + switch (revid & 0xFF) { + case 0x1: + strlcpy(cbuf, "A0", 3); + break; + case 0x3: + strlcpy(cbuf, "A2", 3); + break; + default: + strlcpy(cbuf, "?", 2); + break; + } + dev_info(&port->dd->pdev->dev, + "Card Type: %s\n", cbuf); +} + +/* + * Map the commands scatter list into the command table. + * + * @command Pointer to the command. + * @nents Number of scatter list entries. + * + * return value + * None + */ +static inline void fill_command_sg(struct driver_data *dd, + struct mtip_cmd *command, + int nents) +{ + int n; + unsigned int dma_len; + struct mtip_cmd_sg *command_sg; + struct scatterlist *sg = command->sg; + + command_sg = command->command + AHCI_CMD_TBL_HDR_SZ; + + for (n = 0; n < nents; n++) { + dma_len = sg_dma_len(sg); + if (dma_len > 0x400000) + dev_err(&dd->pdev->dev, + "DMA segment length truncated\n"); + command_sg->info = __force_bit2int + cpu_to_le32((dma_len-1) & 0x3FFFFF); + command_sg->dba = __force_bit2int + cpu_to_le32(sg_dma_address(sg)); + command_sg->dba_upper = __force_bit2int + cpu_to_le32((sg_dma_address(sg) >> 16) >> 16); + command_sg++; + sg++; + } +} + +/* + * @brief Execute a drive command. + * + * return value 0 The command completed successfully. + * return value -1 An error occurred while executing the command. + */ +static int exec_drive_task(struct mtip_port *port, u8 *command) +{ + struct host_to_dev_fis fis; + struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG); + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = command[0]; + fis.features = command[1]; + fis.sect_count = command[2]; + fis.sector = command[3]; + fis.cyl_low = command[4]; + fis.cyl_hi = command[5]; + fis.device = command[6] & ~0x10; /* Clear the dev bit*/ + + + dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, " + "nsect %x, sect %x, lcyl %x, " + "hcyl %x, sel %x\n", + __func__, + command[0], + command[1], + command[2], + command[3], + command[4], + command[5], + command[6]); + + /* Execute the command. */ + if (mtip_exec_internal_command(port, + &fis, + 5, + 0, + 0, + 0, + GFP_KERNEL, + MTIP_IOCTL_COMMAND_TIMEOUT_MS) < 0) { + return -1; + } + + command[0] = reply->command; /* Status*/ + command[1] = reply->features; /* Error*/ + command[4] = reply->cyl_low; + command[5] = reply->cyl_hi; + + dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, " + "err %x , cyl_lo %x cyl_hi %x\n", + __func__, + command[0], + command[1], + command[4], + command[5]); + + return 0; +} + +/* + * @brief Execute a drive command. + * + * @param port Pointer to the port data structure. + * @param command Pointer to the user specified command parameters. + * @param user_buffer Pointer to the user space buffer where read sector + * data should be copied. + * + * return value 0 The command completed successfully. + * return value -EFAULT An error occurred while copying the completion + * data to the user space buffer. + * return value -1 An error occurred while executing the command. + */ +static int exec_drive_command(struct mtip_port *port, u8 *command, + void __user *user_buffer) +{ + struct host_to_dev_fis fis; + struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG); + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = command[0]; + fis.features = command[2]; + fis.sect_count = command[3]; + if (fis.command == ATA_CMD_SMART) { + fis.sector = command[1]; + fis.cyl_low = 0x4F; + fis.cyl_hi = 0xC2; + } + + dbg_printk(MTIP_DRV_NAME + "%s: User Command: cmd %x, sect %x, " + "feat %x, sectcnt %x\n", + __func__, + command[0], + command[1], + command[2], + command[3]); + + memset(port->sector_buffer, 0x00, ATA_SECT_SIZE); + + /* Execute the command. */ + if (mtip_exec_internal_command(port, + &fis, + 5, + port->sector_buffer_dma, + (command[3] != 0) ? ATA_SECT_SIZE : 0, + 0, + GFP_KERNEL, + MTIP_IOCTL_COMMAND_TIMEOUT_MS) + < 0) { + return -1; + } + + /* Collect the completion status. */ + command[0] = reply->command; /* Status*/ + command[1] = reply->features; /* Error*/ + command[2] = command[3]; + + dbg_printk(MTIP_DRV_NAME + "%s: Completion Status: stat %x, " + "err %x, cmd %x\n", + __func__, + command[0], + command[1], + command[2]); + + if (user_buffer && command[3]) { + if (copy_to_user(user_buffer, + port->sector_buffer, + ATA_SECT_SIZE * command[3])) { + return -EFAULT; + } + } + + return 0; +} + +/* + * Indicates whether a command has a single sector payload. + * + * @command passed to the device to perform the certain event. + * @features passed to the device to perform the certain event. + * + * return value + * 1 command is one that always has a single sector payload, + * regardless of the value in the Sector Count field. + * 0 otherwise + * + */ +static unsigned int implicit_sector(unsigned char command, + unsigned char features) +{ + unsigned int rv = 0; + + /* list of commands that have an implicit sector count of 1 */ + switch (command) { + case ATA_CMD_SEC_SET_PASS: + case ATA_CMD_SEC_UNLOCK: + case ATA_CMD_SEC_ERASE_PREP: + case ATA_CMD_SEC_ERASE_UNIT: + case ATA_CMD_SEC_FREEZE_LOCK: + case ATA_CMD_SEC_DISABLE_PASS: + case ATA_CMD_PMP_READ: + case ATA_CMD_PMP_WRITE: + rv = 1; + break; + case ATA_CMD_SET_MAX: + if (features == ATA_SET_MAX_UNLOCK) + rv = 1; + break; + case ATA_CMD_SMART: + if ((features == ATA_SMART_READ_VALUES) || + (features == ATA_SMART_READ_THRESHOLDS)) + rv = 1; + break; + case ATA_CMD_CONF_OVERLAY: + if ((features == ATA_DCO_IDENTIFY) || + (features == ATA_DCO_SET)) + rv = 1; + break; + } + return rv; +} + +/* + * Executes a taskfile + * See ide_taskfile_ioctl() for derivation + */ +static int exec_drive_taskfile(struct driver_data *dd, + void __user *buf, + ide_task_request_t *req_task, + int outtotal) +{ + struct host_to_dev_fis fis; + struct host_to_dev_fis *reply; + u8 *outbuf = NULL; + u8 *inbuf = NULL; + dma_addr_t outbuf_dma = 0; + dma_addr_t inbuf_dma = 0; + dma_addr_t dma_buffer = 0; + int err = 0; + unsigned int taskin = 0; + unsigned int taskout = 0; + u8 nsect = 0; + unsigned int timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; + unsigned int force_single_sector; + unsigned int transfer_size; + unsigned long task_file_data; + int intotal = outtotal + req_task->out_size; + + taskout = req_task->out_size; + taskin = req_task->in_size; + /* 130560 = 512 * 0xFF*/ + if (taskin > 130560 || taskout > 130560) { + err = -EINVAL; + goto abort; + } + + if (taskout) { + outbuf = kzalloc(taskout, GFP_KERNEL); + if (outbuf == NULL) { + err = -ENOMEM; + goto abort; + } + if (copy_from_user(outbuf, buf + outtotal, taskout)) { + err = -EFAULT; + goto abort; + } + outbuf_dma = pci_map_single(dd->pdev, + outbuf, + taskout, + DMA_TO_DEVICE); + if (outbuf_dma == 0) { + err = -ENOMEM; + goto abort; + } + dma_buffer = outbuf_dma; + } + + if (taskin) { + inbuf = kzalloc(taskin, GFP_KERNEL); + if (inbuf == NULL) { + err = -ENOMEM; + goto abort; + } + + if (copy_from_user(inbuf, buf + intotal, taskin)) { + err = -EFAULT; + goto abort; + } + inbuf_dma = pci_map_single(dd->pdev, + inbuf, + taskin, DMA_FROM_DEVICE); + if (inbuf_dma == 0) { + err = -ENOMEM; + goto abort; + } + dma_buffer = inbuf_dma; + } + + /* only supports PIO and non-data commands from this ioctl. */ + switch (req_task->data_phase) { + case TASKFILE_OUT: + nsect = taskout / ATA_SECT_SIZE; + reply = (dd->port->rxfis + RX_FIS_PIO_SETUP); + break; + case TASKFILE_IN: + reply = (dd->port->rxfis + RX_FIS_PIO_SETUP); + break; + case TASKFILE_NO_DATA: + reply = (dd->port->rxfis + RX_FIS_D2H_REG); + break; + default: + err = -EINVAL; + goto abort; + } + + /* Build the FIS. */ + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = req_task->io_ports[7]; + fis.features = req_task->io_ports[1]; + fis.sect_count = req_task->io_ports[2]; + fis.lba_low = req_task->io_ports[3]; + fis.lba_mid = req_task->io_ports[4]; + fis.lba_hi = req_task->io_ports[5]; + /* Clear the dev bit*/ + fis.device = req_task->io_ports[6] & ~0x10; + + if ((req_task->in_flags.all == 0) && (req_task->out_flags.all & 1)) { + req_task->in_flags.all = + IDE_TASKFILE_STD_IN_FLAGS | + (IDE_HOB_STD_IN_FLAGS << 8); + fis.lba_low_ex = req_task->hob_ports[3]; + fis.lba_mid_ex = req_task->hob_ports[4]; + fis.lba_hi_ex = req_task->hob_ports[5]; + fis.features_ex = req_task->hob_ports[1]; + fis.sect_cnt_ex = req_task->hob_ports[2]; + + } else { + req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + } + + force_single_sector = implicit_sector(fis.command, fis.features); + + if ((taskin || taskout) && (!fis.sect_count)) { + if (nsect) + fis.sect_count = nsect; + else { + if (!force_single_sector) { + dev_warn(&dd->pdev->dev, + "data movement but " + "sect_count is 0\n"); + err = -EINVAL; + goto abort; + } + } + } + + dbg_printk(MTIP_DRV_NAME + "taskfile: cmd %x, feat %x, nsect %x," + " sect/lbal %x, lcyl/lbam %x, hcyl/lbah %x," + " head/dev %x\n", + fis.command, + fis.features, + fis.sect_count, + fis.lba_low, + fis.lba_mid, + fis.lba_hi, + fis.device); + + switch (fis.command) { + case ATA_CMD_DOWNLOAD_MICRO: + /* Change timeout for Download Microcode to 60 seconds.*/ + timeout = 60000; + break; + case ATA_CMD_SEC_ERASE_UNIT: + /* Change timeout for Security Erase Unit to 4 minutes.*/ + timeout = 240000; + break; + case ATA_CMD_STANDBYNOW1: + /* Change timeout for standby immediate to 10 seconds.*/ + timeout = 10000; + break; + case 0xF7: + case 0xFA: + /* Change timeout for vendor unique command to 10 secs */ + timeout = 10000; + break; + case ATA_CMD_SMART: + /* Change timeout for vendor unique command to 10 secs */ + timeout = 10000; + break; + default: + timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; + break; + } + + /* Determine the correct transfer size.*/ + if (force_single_sector) + transfer_size = ATA_SECT_SIZE; + else + transfer_size = ATA_SECT_SIZE * fis.sect_count; + + /* Execute the command.*/ + if (mtip_exec_internal_command(dd->port, + &fis, + 5, + dma_buffer, + transfer_size, + 0, + GFP_KERNEL, + timeout) < 0) { + err = -EIO; + goto abort; + } + + task_file_data = readl(dd->port->mmio+PORT_TFDATA); + + if ((req_task->data_phase == TASKFILE_IN) && !(task_file_data & 1)) { + reply = dd->port->rxfis + RX_FIS_PIO_SETUP; + req_task->io_ports[7] = reply->control; + } else { + reply = dd->port->rxfis + RX_FIS_D2H_REG; + req_task->io_ports[7] = reply->command; + } + + /* reclaim the DMA buffers.*/ + if (inbuf_dma) + pci_unmap_single(dd->pdev, inbuf_dma, + taskin, DMA_FROM_DEVICE); + if (outbuf_dma) + pci_unmap_single(dd->pdev, outbuf_dma, + taskout, DMA_TO_DEVICE); + inbuf_dma = 0; + outbuf_dma = 0; + + /* return the ATA registers to the caller.*/ + req_task->io_ports[1] = reply->features; + req_task->io_ports[2] = reply->sect_count; + req_task->io_ports[3] = reply->lba_low; + req_task->io_ports[4] = reply->lba_mid; + req_task->io_ports[5] = reply->lba_hi; + req_task->io_ports[6] = reply->device; + + if (req_task->out_flags.all & 1) { + + req_task->hob_ports[3] = reply->lba_low_ex; + req_task->hob_ports[4] = reply->lba_mid_ex; + req_task->hob_ports[5] = reply->lba_hi_ex; + req_task->hob_ports[1] = reply->features_ex; + req_task->hob_ports[2] = reply->sect_cnt_ex; + } + + /* Com rest after secure erase or lowlevel format */ + if (((fis.command == ATA_CMD_SEC_ERASE_UNIT) || + ((fis.command == 0xFC) && + (fis.features == 0x27 || fis.features == 0x72 || + fis.features == 0x62 || fis.features == 0x26))) && + !(reply->command & 1)) { + mtip_restart_port(dd->port); + } + + dbg_printk(MTIP_DRV_NAME + "%s: Completion: stat %x," + "err %x, sect_cnt %x, lbalo %x," + "lbamid %x, lbahi %x, dev %x\n", + __func__, + req_task->io_ports[7], + req_task->io_ports[1], + req_task->io_ports[2], + req_task->io_ports[3], + req_task->io_ports[4], + req_task->io_ports[5], + req_task->io_ports[6]); + + if (taskout) { + if (copy_to_user(buf + outtotal, outbuf, taskout)) { + err = -EFAULT; + goto abort; + } + } + if (taskin) { + if (copy_to_user(buf + intotal, inbuf, taskin)) { + err = -EFAULT; + goto abort; + } + } +abort: + if (inbuf_dma) + pci_unmap_single(dd->pdev, inbuf_dma, + taskin, DMA_FROM_DEVICE); + if (outbuf_dma) + pci_unmap_single(dd->pdev, outbuf_dma, + taskout, DMA_TO_DEVICE); + kfree(outbuf); + kfree(inbuf); + + return err; +} + +/* + * Handle IOCTL calls from the Block Layer. + * + * This function is called by the Block Layer when it receives an IOCTL + * command that it does not understand. If the IOCTL command is not supported + * this function returns -ENOTTY. + * + * @dd Pointer to the driver data structure. + * @cmd IOCTL command passed from the Block Layer. + * @arg IOCTL argument passed from the Block Layer. + * + * return value + * 0 The IOCTL completed successfully. + * -ENOTTY The specified command is not supported. + * -EFAULT An error occurred copying data to a user space buffer. + * -EIO An error occurred while executing the command. + */ +static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case HDIO_GET_IDENTITY: + if (mtip_get_identify(dd->port, (void __user *) arg) < 0) { + dev_warn(&dd->pdev->dev, + "Unable to read identity\n"); + return -EIO; + } + + break; + case HDIO_DRIVE_CMD: + { + u8 drive_command[4]; + + /* Copy the user command info to our buffer. */ + if (copy_from_user(drive_command, + (void __user *) arg, + sizeof(drive_command))) + return -EFAULT; + + /* Execute the drive command. */ + if (exec_drive_command(dd->port, + drive_command, + (void __user *) (arg+4))) + return -EIO; + + /* Copy the status back to the users buffer. */ + if (copy_to_user((void __user *) arg, + drive_command, + sizeof(drive_command))) + return -EFAULT; + + break; + } + case HDIO_DRIVE_TASK: + { + u8 drive_command[7]; + + /* Copy the user command info to our buffer. */ + if (copy_from_user(drive_command, + (void __user *) arg, + sizeof(drive_command))) + return -EFAULT; + + /* Execute the drive command. */ + if (exec_drive_task(dd->port, drive_command)) + return -EIO; + + /* Copy the status back to the users buffer. */ + if (copy_to_user((void __user *) arg, + drive_command, + sizeof(drive_command))) + return -EFAULT; + + break; + } + case HDIO_DRIVE_TASKFILE: { + ide_task_request_t req_task; + int ret, outtotal; + + if (copy_from_user(&req_task, (void __user *) arg, + sizeof(req_task))) + return -EFAULT; + + outtotal = sizeof(req_task); + + ret = exec_drive_taskfile(dd, (void __user *) arg, + &req_task, outtotal); + + if (copy_to_user((void __user *) arg, &req_task, + sizeof(req_task))) + return -EFAULT; + + return ret; + } + + default: + return -EINVAL; + } + return 0; +} + +/* + * Submit an IO to the hw + * + * This function is called by the block layer to issue an io + * to the device. Upon completion, the callback function will + * be called with the data parameter passed as the callback data. + * + * @dd Pointer to the driver data structure. + * @start First sector to read. + * @nsect Number of sectors to read. + * @nents Number of entries in scatter list for the read command. + * @tag The tag of this read command. + * @callback Pointer to the function that should be called + * when the read completes. + * @data Callback data passed to the callback function + * when the read completes. + * @barrier If non-zero, this command must be completed before + * issuing any other commands. + * @dir Direction (read or write) + * + * return value + * None + */ +static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, + int nsect, int nents, int tag, void *callback, + void *data, int barrier, int dir) +{ + struct host_to_dev_fis *fis; + struct mtip_port *port = dd->port; + struct mtip_cmd *command = &port->commands[tag]; + + /* Map the scatter list for DMA access */ + if (dir == READ) + nents = dma_map_sg(&dd->pdev->dev, command->sg, + nents, DMA_FROM_DEVICE); + else + nents = dma_map_sg(&dd->pdev->dev, command->sg, + nents, DMA_TO_DEVICE); + + command->scatter_ents = nents; + + /* + * The number of retries for this command before it is + * reported as a failure to the upper layers. + */ + command->retries = MTIP_MAX_RETRIES; + + /* Fill out fis */ + fis = command->command; + fis->type = 0x27; + fis->opts = 1 << 7; + fis->command = + (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE); + *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF); + *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF); + fis->device = 1 << 6; + if (barrier) + fis->device |= FUA_BIT; + fis->features = nsect & 0xFF; + fis->features_ex = (nsect >> 8) & 0xFF; + fis->sect_count = ((tag << 3) | (tag >> 5)); + fis->sect_cnt_ex = 0; + fis->control = 0; + fis->res2 = 0; + fis->res3 = 0; + fill_command_sg(dd, command, nents); + + /* Populate the command header */ + command->command_header->opts = + __force_bit2int cpu_to_le32( + (nents << 16) | 5 | AHCI_CMD_PREFETCH); + command->command_header->byte_count = 0; + + /* + * Set the completion function and data for the command + * within this layer. + */ + command->comp_data = dd; + command->comp_func = mtip_async_complete; + command->direction = (dir == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + + /* + * Set the completion function and data for the command passed + * from the upper layer. + */ + command->async_data = data; + command->async_callback = callback; + + /* + * To prevent this command from being issued + * if an internal command is in progress or error handling is active. + */ + if (unlikely(test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) || + test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags))) { + set_bit(tag, port->cmds_to_issue); + set_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); + return; + } + + /* Issue the command to the hardware */ + mtip_issue_ncq_command(port, tag); + + /* Set the command's timeout value.*/ + port->commands[tag].comp_time = jiffies + msecs_to_jiffies( + MTIP_NCQ_COMMAND_TIMEOUT_MS); +} + +/* + * Release a command slot. + * + * @dd Pointer to the driver data structure. + * @tag Slot tag + * + * return value + * None + */ +static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag) +{ + release_slot(dd->port, tag); +} + +/* + * Obtain a command slot and return its associated scatter list. + * + * @dd Pointer to the driver data structure. + * @tag Pointer to an int that will receive the allocated command + * slot tag. + * + * return value + * Pointer to the scatter list for the allocated command slot + * or NULL if no command slots are available. + */ +static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, + int *tag) +{ + /* + * It is possible that, even with this semaphore, a thread + * may think that no command slots are available. Therefore, we + * need to make an attempt to get_slot(). + */ + down(&dd->port->cmd_slot); + *tag = get_slot(dd->port); + + if (unlikely(*tag < 0)) + return NULL; + + return dd->port->commands[*tag].sg; +} + +/* + * Sysfs register/status dump. + * + * @dev Pointer to the device structure, passed by the kernrel. + * @attr Pointer to the device_attribute structure passed by the kernel. + * @buf Pointer to the char buffer that will receive the stats info. + * + * return value + * The size, in bytes, of the data copied into buf. + */ +static ssize_t hw_show_registers(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 group_allocated; + struct driver_data *dd = dev_to_disk(dev)->private_data; + int size = 0; + int n; + + size += sprintf(&buf[size], "%s:\ns_active:\n", __func__); + + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->s_active[n])); + + size += sprintf(&buf[size], "Command Issue:\n"); + + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->cmd_issue[n])); + + size += sprintf(&buf[size], "Allocated:\n"); + + for (n = 0; n < dd->slot_groups; n++) { + if (sizeof(long) > sizeof(u32)) + group_allocated = + dd->port->allocated[n/2] >> (32*(n&1)); + else + group_allocated = dd->port->allocated[n]; + size += sprintf(&buf[size], "0x%08x\n", + group_allocated); + } + + size += sprintf(&buf[size], "completed:\n"); + + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->completed[n])); + + size += sprintf(&buf[size], "PORT_IRQ_STAT 0x%08x\n", + readl(dd->port->mmio + PORT_IRQ_STAT)); + size += sprintf(&buf[size], "HOST_IRQ_STAT 0x%08x\n", + readl(dd->mmio + HOST_IRQ_STAT)); + + return size; +} +static DEVICE_ATTR(registers, S_IRUGO, hw_show_registers, NULL); + +/* + * Create the sysfs related attributes. + * + * @dd Pointer to the driver data structure. + * @kobj Pointer to the kobj for the block device. + * + * return value + * 0 Operation completed successfully. + * -EINVAL Invalid parameter. + */ +static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) +{ + if (!kobj || !dd) + return -EINVAL; + + if (sysfs_create_file(kobj, &dev_attr_registers.attr)) + dev_warn(&dd->pdev->dev, + "Error creating registers sysfs entry\n"); + return 0; +} + +/* + * Remove the sysfs related attributes. + * + * @dd Pointer to the driver data structure. + * @kobj Pointer to the kobj for the block device. + * + * return value + * 0 Operation completed successfully. + * -EINVAL Invalid parameter. + */ +static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) +{ + if (!kobj || !dd) + return -EINVAL; + + sysfs_remove_file(kobj, &dev_attr_registers.attr); + + return 0; +} + +/* + * Perform any init/resume time hardware setup + * + * @dd Pointer to the driver data structure. + * + * return value + * None + */ +static inline void hba_setup(struct driver_data *dd) +{ + u32 hwdata; + hwdata = readl(dd->mmio + HOST_HSORG); + + /* interrupt bug workaround: use only 1 IS bit.*/ + writel(hwdata | + HSORG_DISABLE_SLOTGRP_INTR | + HSORG_DISABLE_SLOTGRP_PXIS, + dd->mmio + HOST_HSORG); +} + +/* + * Detect the details of the product, and store anything needed + * into the driver data structure. This includes product type and + * version and number of slot groups. + * + * @dd Pointer to the driver data structure. + * + * return value + * None + */ +static void mtip_detect_product(struct driver_data *dd) +{ + u32 hwdata; + unsigned int rev, slotgroups; + + /* + * HBA base + 0xFC [15:0] - vendor-specific hardware interface + * info register: + * [15:8] hardware/software interface rev# + * [ 3] asic-style interface + * [ 2:0] number of slot groups, minus 1 (only valid for asic-style). + */ + hwdata = readl(dd->mmio + HOST_HSORG); + + dd->product_type = MTIP_PRODUCT_UNKNOWN; + dd->slot_groups = 1; + + if (hwdata & 0x8) { + dd->product_type = MTIP_PRODUCT_ASICFPGA; + rev = (hwdata & HSORG_HWREV) >> 8; + slotgroups = (hwdata & HSORG_SLOTGROUPS) + 1; + dev_info(&dd->pdev->dev, + "ASIC-FPGA design, HS rev 0x%x, " + "%i slot groups [%i slots]\n", + rev, + slotgroups, + slotgroups * 32); + + if (slotgroups > MTIP_MAX_SLOT_GROUPS) { + dev_warn(&dd->pdev->dev, + "Warning: driver only supports " + "%i slot groups.\n", MTIP_MAX_SLOT_GROUPS); + slotgroups = MTIP_MAX_SLOT_GROUPS; + } + dd->slot_groups = slotgroups; + return; + } + + dev_warn(&dd->pdev->dev, "Unrecognized product id\n"); +} + +/* + * Blocking wait for FTL rebuild to complete + * + * @dd Pointer to the DRIVER_DATA structure. + * + * return value + * 0 FTL rebuild completed successfully + * -EFAULT FTL rebuild error/timeout/interruption + */ +static int mtip_ftl_rebuild_poll(struct driver_data *dd) +{ + unsigned long timeout, cnt = 0, start; + + dev_warn(&dd->pdev->dev, + "FTL rebuild in progress. Polling for completion.\n"); + + start = jiffies; + dd->ftlrebuildflag = 1; + timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS); + + do { + if (mtip_check_surprise_removal(dd->pdev)) + return -EFAULT; + + if (mtip_get_identify(dd->port, NULL) < 0) + return -EFAULT; + + if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == + MTIP_FTL_REBUILD_MAGIC) { + ssleep(1); + /* Print message every 3 minutes */ + if (cnt++ >= 180) { + dev_warn(&dd->pdev->dev, + "FTL rebuild in progress (%d secs).\n", + jiffies_to_msecs(jiffies - start) / 1000); + cnt = 0; + } + } else { + dev_warn(&dd->pdev->dev, + "FTL rebuild complete (%d secs).\n", + jiffies_to_msecs(jiffies - start) / 1000); + dd->ftlrebuildflag = 0; + mtip_block_initialize(dd); + break; + } + ssleep(10); + } while (time_before(jiffies, timeout)); + + /* Check for timeout */ + if (dd->ftlrebuildflag) { + dev_err(&dd->pdev->dev, + "Timed out waiting for FTL rebuild to complete (%d secs).\n", + jiffies_to_msecs(jiffies - start) / 1000); + return -EFAULT; + } + + return 0; +} + +/* + * service thread to issue queued commands + * + * @data Pointer to the driver data structure. + * + * return value + * 0 + */ + +static int mtip_service_thread(void *data) +{ + struct driver_data *dd = (struct driver_data *)data; + unsigned long slot, slot_start, slot_wrap; + unsigned int num_cmd_slots = dd->slot_groups * 32; + struct mtip_port *port = dd->port; + + while (1) { + /* + * the condition is to check neither an internal command is + * is in progress nor error handling is active + */ + wait_event_interruptible(port->svc_wait, (port->flags) && + !test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && + !test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags)); + + if (kthread_should_stop()) + break; + + set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); + if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + slot = 1; + /* used to restrict the loop to one iteration */ + slot_start = num_cmd_slots; + slot_wrap = 0; + while (1) { + slot = find_next_bit(port->cmds_to_issue, + num_cmd_slots, slot); + if (slot_wrap == 1) { + if ((slot_start >= slot) || + (slot >= num_cmd_slots)) + break; + } + if (unlikely(slot_start == num_cmd_slots)) + slot_start = slot; + + if (unlikely(slot == num_cmd_slots)) { + slot = 1; + slot_wrap = 1; + continue; + } + + /* Issue the command to the hardware */ + mtip_issue_ncq_command(port, slot); + + /* Set the command's timeout value.*/ + port->commands[slot].comp_time = jiffies + + msecs_to_jiffies(MTIP_NCQ_COMMAND_TIMEOUT_MS); + + clear_bit(slot, port->cmds_to_issue); + } + + clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); + } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) { + mtip_ftl_rebuild_poll(dd); + clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags); + } + clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); + + if (test_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &port->flags)) + break; + } + return 0; +} + +/* + * Called once for each card. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 on success, else an error code. + */ +static int mtip_hw_init(struct driver_data *dd) +{ + int i; + int rv; + unsigned int num_command_slots; + + dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; + + mtip_detect_product(dd); + if (dd->product_type == MTIP_PRODUCT_UNKNOWN) { + rv = -EIO; + goto out1; + } + num_command_slots = dd->slot_groups * 32; + + hba_setup(dd); + + tasklet_init(&dd->tasklet, mtip_tasklet, (unsigned long)dd); + + dd->port = kzalloc(sizeof(struct mtip_port), GFP_KERNEL); + if (!dd->port) { + dev_err(&dd->pdev->dev, + "Memory allocation: port structure\n"); + return -ENOMEM; + } + + /* Counting semaphore to track command slot usage */ + sema_init(&dd->port->cmd_slot, num_command_slots - 1); + + /* Spinlock to prevent concurrent issue */ + spin_lock_init(&dd->port->cmd_issue_lock); + + /* Set the port mmio base address. */ + dd->port->mmio = dd->mmio + PORT_OFFSET; + dd->port->dd = dd; + + /* Allocate memory for the command list. */ + dd->port->command_list = + dmam_alloc_coherent(&dd->pdev->dev, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + &dd->port->command_list_dma, + GFP_KERNEL); + if (!dd->port->command_list) { + dev_err(&dd->pdev->dev, + "Memory allocation: command list\n"); + rv = -ENOMEM; + goto out1; + } + + /* Clear the memory we have allocated. */ + memset(dd->port->command_list, + 0, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2)); + + /* Setup the addresse of the RX FIS. */ + dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; + dd->port->rxfis_dma = dd->port->command_list_dma + HW_CMD_SLOT_SZ; + + /* Setup the address of the command tables. */ + dd->port->command_table = dd->port->rxfis + AHCI_RX_FIS_SZ; + dd->port->command_tbl_dma = dd->port->rxfis_dma + AHCI_RX_FIS_SZ; + + /* Setup the address of the identify data. */ + dd->port->identify = dd->port->command_table + + HW_CMD_TBL_AR_SZ; + dd->port->identify_dma = dd->port->command_tbl_dma + + HW_CMD_TBL_AR_SZ; + + /* Setup the address of the sector buffer. */ + dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; + dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; + + /* Point the command headers at the command tables. */ + for (i = 0; i < num_command_slots; i++) { + dd->port->commands[i].command_header = + dd->port->command_list + + (sizeof(struct mtip_cmd_hdr) * i); + dd->port->commands[i].command_header_dma = + dd->port->command_list_dma + + (sizeof(struct mtip_cmd_hdr) * i); + + dd->port->commands[i].command = + dd->port->command_table + (HW_CMD_TBL_SZ * i); + dd->port->commands[i].command_dma = + dd->port->command_tbl_dma + (HW_CMD_TBL_SZ * i); + + if (readl(dd->mmio + HOST_CAP) & HOST_CAP_64) + dd->port->commands[i].command_header->ctbau = + __force_bit2int cpu_to_le32( + (dd->port->commands[i].command_dma >> 16) >> 16); + dd->port->commands[i].command_header->ctba = + __force_bit2int cpu_to_le32( + dd->port->commands[i].command_dma & 0xFFFFFFFF); + + /* + * If this is not done, a bug is reported by the stock + * FC11 i386. Due to the fact that it has lots of kernel + * debugging enabled. + */ + sg_init_table(dd->port->commands[i].sg, MTIP_MAX_SG); + + /* Mark all commands as currently inactive.*/ + atomic_set(&dd->port->commands[i].active, 0); + } + + /* Setup the pointers to the extended s_active and CI registers. */ + for (i = 0; i < dd->slot_groups; i++) { + dd->port->s_active[i] = + dd->port->mmio + i*0x80 + PORT_SCR_ACT; + dd->port->cmd_issue[i] = + dd->port->mmio + i*0x80 + PORT_COMMAND_ISSUE; + dd->port->completed[i] = + dd->port->mmio + i*0x80 + PORT_SDBV; + } + + /* Reset the HBA. */ + if (mtip_hba_reset(dd) < 0) { + dev_err(&dd->pdev->dev, + "Card did not reset within timeout\n"); + rv = -EIO; + goto out2; + } + + mtip_init_port(dd->port); + mtip_start_port(dd->port); + + /* Setup the ISR and enable interrupts. */ + rv = devm_request_irq(&dd->pdev->dev, + dd->pdev->irq, + mtip_irq_handler, + IRQF_SHARED, + dev_driver_string(&dd->pdev->dev), + dd); + + if (rv) { + dev_err(&dd->pdev->dev, + "Unable to allocate IRQ %d\n", dd->pdev->irq); + goto out2; + } + + /* Enable interrupts on the HBA. */ + writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN, + dd->mmio + HOST_CTL); + + init_timer(&dd->port->cmd_timer); + init_waitqueue_head(&dd->port->svc_wait); + + dd->port->cmd_timer.data = (unsigned long int) dd->port; + dd->port->cmd_timer.function = mtip_timeout_function; + mod_timer(&dd->port->cmd_timer, + jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); + + if (mtip_get_identify(dd->port, NULL) < 0) { + rv = -EFAULT; + goto out3; + } + + if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == + MTIP_FTL_REBUILD_MAGIC) { + set_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags); + return MTIP_FTL_REBUILD_MAGIC; + } + mtip_dump_identify(dd->port); + return rv; + +out3: + del_timer_sync(&dd->port->cmd_timer); + + /* Disable interrupts on the HBA. */ + writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, + dd->mmio + HOST_CTL); + + /*Release the IRQ. */ + devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd); + +out2: + mtip_deinit_port(dd->port); + + /* Free the command/command header memory. */ + dmam_free_coherent(&dd->pdev->dev, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + dd->port->command_list, + dd->port->command_list_dma); +out1: + /* Free the memory allocated for the for structure. */ + kfree(dd->port); + + return rv; +} + +/* + * Called to deinitialize an interface. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_hw_exit(struct driver_data *dd) +{ + /* + * Send standby immediate (E0h) to the drive so that it + * saves its state. + */ + if (atomic_read(&dd->drv_cleanup_done) != true) { + + mtip_standby_immediate(dd->port); + + /* de-initialize the port. */ + mtip_deinit_port(dd->port); + + /* Disable interrupts on the HBA. */ + writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, + dd->mmio + HOST_CTL); + } + + del_timer_sync(&dd->port->cmd_timer); + + /* Release the IRQ. */ + devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd); + + /* Stop the bottom half tasklet. */ + tasklet_kill(&dd->tasklet); + + /* Free the command/command header memory. */ + dmam_free_coherent(&dd->pdev->dev, + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + dd->port->command_list, + dd->port->command_list_dma); + /* Free the memory allocated for the for structure. */ + kfree(dd->port); + + return 0; +} + +/* + * Issue a Standby Immediate command to the device. + * + * This function is called by the Block Layer just before the + * system powers off during a shutdown. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_hw_shutdown(struct driver_data *dd) +{ + /* + * Send standby immediate (E0h) to the drive so that it + * saves its state. + */ + mtip_standby_immediate(dd->port); + + return 0; +} + +/* + * Suspend function + * + * This function is called by the Block Layer just before the + * system hibernates. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 Suspend was successful + * -EFAULT Suspend was not successful + */ +static int mtip_hw_suspend(struct driver_data *dd) +{ + /* + * Send standby immediate (E0h) to the drive + * so that it saves its state. + */ + if (mtip_standby_immediate(dd->port) != 0) { + dev_err(&dd->pdev->dev, + "Failed standby-immediate command\n"); + return -EFAULT; + } + + /* Disable interrupts on the HBA.*/ + writel(readl(dd->mmio + HOST_CTL) & ~HOST_IRQ_EN, + dd->mmio + HOST_CTL); + mtip_deinit_port(dd->port); + + return 0; +} + +/* + * Resume function + * + * This function is called by the Block Layer as the + * system resumes. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 Resume was successful + * -EFAULT Resume was not successful + */ +static int mtip_hw_resume(struct driver_data *dd) +{ + /* Perform any needed hardware setup steps */ + hba_setup(dd); + + /* Reset the HBA */ + if (mtip_hba_reset(dd) != 0) { + dev_err(&dd->pdev->dev, + "Unable to reset the HBA\n"); + return -EFAULT; + } + + /* + * Enable the port, DMA engine, and FIS reception specific + * h/w in controller. + */ + mtip_init_port(dd->port); + mtip_start_port(dd->port); + + /* Enable interrupts on the HBA.*/ + writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN, + dd->mmio + HOST_CTL); + + return 0; +} + +/* + * Helper function for reusing disk name + * upon hot insertion. + */ +static int rssd_disk_name_format(char *prefix, + int index, + char *buf, + int buflen) +{ + const int base = 'z' - 'a' + 1; + char *begin = buf + strlen(prefix); + char *end = buf + buflen; + char *p; + int unit; + + p = end - 1; + *p = '\0'; + unit = base; + do { + if (p == begin) + return -EINVAL; + *--p = 'a' + (index % unit); + index = (index / unit) - 1; + } while (index >= 0); + + memmove(begin, p, end - p); + memcpy(buf, prefix, strlen(prefix)); + + return 0; +} + +/* + * Block layer IOCTL handler. + * + * @dev Pointer to the block_device structure. + * @mode ignored + * @cmd IOCTL command passed from the user application. + * @arg Argument passed from the user application. + * + * return value + * 0 IOCTL completed successfully. + * -ENOTTY IOCTL not supported or invalid driver data + * structure pointer. + */ +static int mtip_block_ioctl(struct block_device *dev, + fmode_t mode, + unsigned cmd, + unsigned long arg) +{ + struct driver_data *dd = dev->bd_disk->private_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (!dd) + return -ENOTTY; + + switch (cmd) { + case BLKFLSBUF: + return -ENOTTY; + default: + return mtip_hw_ioctl(dd, cmd, arg); + } +} + +#ifdef CONFIG_COMPAT +/* + * Block layer compat IOCTL handler. + * + * @dev Pointer to the block_device structure. + * @mode ignored + * @cmd IOCTL command passed from the user application. + * @arg Argument passed from the user application. + * + * return value + * 0 IOCTL completed successfully. + * -ENOTTY IOCTL not supported or invalid driver data + * structure pointer. + */ +static int mtip_block_compat_ioctl(struct block_device *dev, + fmode_t mode, + unsigned cmd, + unsigned long arg) +{ + struct driver_data *dd = dev->bd_disk->private_data; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (!dd) + return -ENOTTY; + + switch (cmd) { + case BLKFLSBUF: + return -ENOTTY; + case HDIO_DRIVE_TASKFILE: { + struct mtip_compat_ide_task_request_s __user *compat_req_task; + ide_task_request_t req_task; + int compat_tasksize, outtotal, ret; + + compat_tasksize = + sizeof(struct mtip_compat_ide_task_request_s); + + compat_req_task = + (struct mtip_compat_ide_task_request_s __user *) arg; + + if (copy_from_user(&req_task, (void __user *) arg, + compat_tasksize - (2 * sizeof(compat_long_t)))) + return -EFAULT; + + if (get_user(req_task.out_size, &compat_req_task->out_size)) + return -EFAULT; + + if (get_user(req_task.in_size, &compat_req_task->in_size)) + return -EFAULT; + + outtotal = sizeof(struct mtip_compat_ide_task_request_s); + + ret = exec_drive_taskfile(dd, (void __user *) arg, + &req_task, outtotal); + + if (copy_to_user((void __user *) arg, &req_task, + compat_tasksize - + (2 * sizeof(compat_long_t)))) + return -EFAULT; + + if (put_user(req_task.out_size, &compat_req_task->out_size)) + return -EFAULT; + + if (put_user(req_task.in_size, &compat_req_task->in_size)) + return -EFAULT; + + return ret; + } + default: + return mtip_hw_ioctl(dd, cmd, arg); + } +} +#endif + +/* + * Obtain the geometry of the device. + * + * You may think that this function is obsolete, but some applications, + * fdisk for example still used CHS values. This function describes the + * device as having 224 heads and 56 sectors per cylinder. These values are + * chosen so that each cylinder is aligned on a 4KB boundary. Since a + * partition is described in terms of a start and end cylinder this means + * that each partition is also 4KB aligned. Non-aligned partitions adversely + * affects performance. + * + * @dev Pointer to the block_device strucutre. + * @geo Pointer to a hd_geometry structure. + * + * return value + * 0 Operation completed successfully. + * -ENOTTY An error occurred while reading the drive capacity. + */ +static int mtip_block_getgeo(struct block_device *dev, + struct hd_geometry *geo) +{ + struct driver_data *dd = dev->bd_disk->private_data; + sector_t capacity; + + if (!dd) + return -ENOTTY; + + if (!(mtip_hw_get_capacity(dd, &capacity))) { + dev_warn(&dd->pdev->dev, + "Could not get drive capacity.\n"); + return -ENOTTY; + } + + geo->heads = 224; + geo->sectors = 56; + sector_div(capacity, (geo->heads * geo->sectors)); + geo->cylinders = capacity; + return 0; +} + +/* + * Block device operation function. + * + * This structure contains pointers to the functions required by the block + * layer. + */ +static const struct block_device_operations mtip_block_ops = { + .ioctl = mtip_block_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mtip_block_compat_ioctl, +#endif + .getgeo = mtip_block_getgeo, + .owner = THIS_MODULE +}; + +/* + * Block layer make request function. + * + * This function is called by the kernel to process a BIO for + * the P320 device. + * + * @queue Pointer to the request queue. Unused other than to obtain + * the driver data structure. + * @bio Pointer to the BIO. + * + */ +static void mtip_make_request(struct request_queue *queue, struct bio *bio) +{ + struct driver_data *dd = queue->queuedata; + struct scatterlist *sg; + struct bio_vec *bvec; + int nents = 0; + int tag = 0; + + if (unlikely(!bio_has_data(bio))) { + blk_queue_flush(queue, 0); + bio_endio(bio, 0); + return; + } + + sg = mtip_hw_get_scatterlist(dd, &tag); + if (likely(sg != NULL)) { + blk_queue_bounce(queue, &bio); + + if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) { + dev_warn(&dd->pdev->dev, + "Maximum number of SGL entries exceeded"); + bio_io_error(bio); + mtip_hw_release_scatterlist(dd, tag); + return; + } + + /* Create the scatter list for this bio. */ + bio_for_each_segment(bvec, bio, nents) { + sg_set_page(&sg[nents], + bvec->bv_page, + bvec->bv_len, + bvec->bv_offset); + } + + /* Issue the read/write. */ + mtip_hw_submit_io(dd, + bio->bi_sector, + bio_sectors(bio), + nents, + tag, + bio_endio, + bio, + bio->bi_rw & REQ_FUA, + bio_data_dir(bio)); + } else + bio_io_error(bio); +} + +/* + * Block layer initialization function. + * + * This function is called once by the PCI layer for each P320 + * device that is connected to the system. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 on success else an error code. + */ +static int mtip_block_initialize(struct driver_data *dd) +{ + int rv = 0, wait_for_rebuild = 0; + sector_t capacity; + unsigned int index = 0; + struct kobject *kobj; + unsigned char thd_name[16]; + + if (dd->disk) + goto skip_create_disk; /* hw init done, before rebuild */ + + /* Initialize the protocol layer. */ + wait_for_rebuild = mtip_hw_init(dd); + if (wait_for_rebuild < 0) { + dev_err(&dd->pdev->dev, + "Protocol layer initialization failed\n"); + rv = -EINVAL; + goto protocol_init_error; + } + + dd->disk = alloc_disk(MTIP_MAX_MINORS); + if (dd->disk == NULL) { + dev_err(&dd->pdev->dev, + "Unable to allocate gendisk structure\n"); + rv = -EINVAL; + goto alloc_disk_error; + } + + /* Generate the disk name, implemented same as in sd.c */ + do { + if (!ida_pre_get(&rssd_index_ida, GFP_KERNEL)) + goto ida_get_error; + + spin_lock(&rssd_index_lock); + rv = ida_get_new(&rssd_index_ida, &index); + spin_unlock(&rssd_index_lock); + } while (rv == -EAGAIN); + + if (rv) + goto ida_get_error; + + rv = rssd_disk_name_format("rssd", + index, + dd->disk->disk_name, + DISK_NAME_LEN); + if (rv) + goto disk_index_error; + + dd->disk->driverfs_dev = &dd->pdev->dev; + dd->disk->major = dd->major; + dd->disk->first_minor = dd->instance * MTIP_MAX_MINORS; + dd->disk->fops = &mtip_block_ops; + dd->disk->private_data = dd; + dd->index = index; + + /* + * if rebuild pending, start the service thread, and delay the block + * queue creation and add_disk() + */ + if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC) + goto start_service_thread; + +skip_create_disk: + /* Allocate the request queue. */ + dd->queue = blk_alloc_queue(GFP_KERNEL); + if (dd->queue == NULL) { + dev_err(&dd->pdev->dev, + "Unable to allocate request queue\n"); + rv = -ENOMEM; + goto block_queue_alloc_init_error; + } + + /* Attach our request function to the request queue. */ + blk_queue_make_request(dd->queue, mtip_make_request); + + dd->disk->queue = dd->queue; + dd->queue->queuedata = dd; + + /* Set device limits. */ + set_bit(QUEUE_FLAG_NONROT, &dd->queue->queue_flags); + blk_queue_max_segments(dd->queue, MTIP_MAX_SG); + blk_queue_physical_block_size(dd->queue, 4096); + blk_queue_io_min(dd->queue, 4096); + blk_queue_flush(dd->queue, 0); + + /* Set the capacity of the device in 512 byte sectors. */ + if (!(mtip_hw_get_capacity(dd, &capacity))) { + dev_warn(&dd->pdev->dev, + "Could not read drive capacity\n"); + rv = -EIO; + goto read_capacity_error; + } + set_capacity(dd->disk, capacity); + + /* Enable the block device and add it to /dev */ + add_disk(dd->disk); + + /* + * Now that the disk is active, initialize any sysfs attributes + * managed by the protocol layer. + */ + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_init(dd, kobj); + kobject_put(kobj); + } + + if (dd->mtip_svc_handler) + return rv; /* service thread created for handling rebuild */ + +start_service_thread: + sprintf(thd_name, "mtip_svc_thd_%02d", index); + + dd->mtip_svc_handler = kthread_run(mtip_service_thread, + dd, thd_name); + + if (IS_ERR(dd->mtip_svc_handler)) { + printk(KERN_ERR "mtip32xx: service thread failed to start\n"); + dd->mtip_svc_handler = NULL; + rv = -EFAULT; + goto kthread_run_error; + } + + return rv; + +kthread_run_error: + /* Delete our gendisk. This also removes the device from /dev */ + del_gendisk(dd->disk); + +read_capacity_error: + blk_cleanup_queue(dd->queue); + +block_queue_alloc_init_error: +disk_index_error: + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, index); + spin_unlock(&rssd_index_lock); + +ida_get_error: + put_disk(dd->disk); + +alloc_disk_error: + mtip_hw_exit(dd); /* De-initialize the protocol layer. */ + +protocol_init_error: + return rv; +} + +/* + * Block layer deinitialization function. + * + * Called by the PCI layer as each P320 device is removed. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_block_remove(struct driver_data *dd) +{ + struct kobject *kobj; + + if (dd->mtip_svc_handler) { + set_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); + wake_up_interruptible(&dd->port->svc_wait); + kthread_stop(dd->mtip_svc_handler); + } + + /* Clean up the sysfs attributes managed by the protocol layer. */ + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_exit(dd, kobj); + kobject_put(kobj); + } + + /* + * Delete our gendisk structure. This also removes the device + * from /dev + */ + del_gendisk(dd->disk); + blk_cleanup_queue(dd->queue); + dd->disk = NULL; + dd->queue = NULL; + + /* De-initialize the protocol layer. */ + mtip_hw_exit(dd); + + return 0; +} + +/* + * Function called by the PCI layer when just before the + * machine shuts down. + * + * If a protocol layer shutdown function is present it will be called + * by this function. + * + * @dd Pointer to the driver data structure. + * + * return value + * 0 + */ +static int mtip_block_shutdown(struct driver_data *dd) +{ + dev_info(&dd->pdev->dev, + "Shutting down %s ...\n", dd->disk->disk_name); + + /* Delete our gendisk structure, and cleanup the blk queue. */ + del_gendisk(dd->disk); + blk_cleanup_queue(dd->queue); + dd->disk = NULL; + dd->queue = NULL; + + mtip_hw_shutdown(dd); + return 0; +} + +static int mtip_block_suspend(struct driver_data *dd) +{ + dev_info(&dd->pdev->dev, + "Suspending %s ...\n", dd->disk->disk_name); + mtip_hw_suspend(dd); + return 0; +} + +static int mtip_block_resume(struct driver_data *dd) +{ + dev_info(&dd->pdev->dev, "Resuming %s ...\n", + dd->disk->disk_name); + mtip_hw_resume(dd); + return 0; +} + +/* + * Called for each supported PCI device detected. + * + * This function allocates the private data structure, enables the + * PCI device and then calls the block layer initialization function. + * + * return value + * 0 on success else an error code. + */ +static int mtip_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int rv = 0; + struct driver_data *dd = NULL; + + /* Allocate memory for this devices private data. */ + dd = kzalloc(sizeof(struct driver_data), GFP_KERNEL); + if (dd == NULL) { + dev_err(&pdev->dev, + "Unable to allocate memory for driver data\n"); + return -ENOMEM; + } + + /* Set the atomic variable as 1 in case of SRSI */ + atomic_set(&dd->drv_cleanup_done, true); + + atomic_set(&dd->resumeflag, false); + + /* Attach the private data to this PCI device. */ + pci_set_drvdata(pdev, dd); + + rv = pcim_enable_device(pdev); + if (rv < 0) { + dev_err(&pdev->dev, "Unable to enable device\n"); + goto iomap_err; + } + + /* Map BAR5 to memory. */ + rv = pcim_iomap_regions(pdev, 1 << MTIP_ABAR, MTIP_DRV_NAME); + if (rv < 0) { + dev_err(&pdev->dev, "Unable to map regions\n"); + goto iomap_err; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + rv = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + + if (rv) { + rv = pci_set_consistent_dma_mask(pdev, + DMA_BIT_MASK(32)); + if (rv) { + dev_warn(&pdev->dev, + "64-bit DMA enable failed\n"); + goto setmask_err; + } + } + } + + pci_set_master(pdev); + + if (pci_enable_msi(pdev)) { + dev_warn(&pdev->dev, + "Unable to enable MSI interrupt.\n"); + goto block_initialize_err; + } + + /* Copy the info we may need later into the private data structure. */ + dd->major = mtip_major; + dd->instance = instance; + dd->pdev = pdev; + + /* Initialize the block layer. */ + rv = mtip_block_initialize(dd); + if (rv < 0) { + dev_err(&pdev->dev, + "Unable to initialize block layer\n"); + goto block_initialize_err; + } + + /* + * Increment the instance count so that each device has a unique + * instance number. + */ + instance++; + + goto done; + +block_initialize_err: + pci_disable_msi(pdev); + +setmask_err: + pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); + +iomap_err: + kfree(dd); + pci_set_drvdata(pdev, NULL); + return rv; +done: + /* Set the atomic variable as 0 in case of SRSI */ + atomic_set(&dd->drv_cleanup_done, true); + + return rv; +} + +/* + * Called for each probed device when the device is removed or the + * driver is unloaded. + * + * return value + * None + */ +static void mtip_pci_remove(struct pci_dev *pdev) +{ + struct driver_data *dd = pci_get_drvdata(pdev); + int counter = 0; + + if (mtip_check_surprise_removal(pdev)) { + while (atomic_read(&dd->drv_cleanup_done) == false) { + counter++; + msleep(20); + if (counter == 10) { + /* Cleanup the outstanding commands */ + mtip_command_cleanup(dd); + break; + } + } + } + /* Set the atomic variable as 1 in case of SRSI */ + atomic_set(&dd->drv_cleanup_done, true); + + /* Clean up the block layer. */ + mtip_block_remove(dd); + + pci_disable_msi(pdev); + + kfree(dd); + pcim_iounmap_regions(pdev, 1 << MTIP_ABAR); +} + +/* + * Called for each probed device when the device is suspended. + * + * return value + * 0 Success + * <0 Error + */ +static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + int rv = 0; + struct driver_data *dd = pci_get_drvdata(pdev); + + if (!dd) { + dev_err(&pdev->dev, + "Driver private datastructure is NULL\n"); + return -EFAULT; + } + + atomic_set(&dd->resumeflag, true); + + /* Disable ports & interrupts then send standby immediate */ + rv = mtip_block_suspend(dd); + if (rv < 0) { + dev_err(&pdev->dev, + "Failed to suspend controller\n"); + return rv; + } + + /* + * Save the pci config space to pdev structure & + * disable the device + */ + pci_save_state(pdev); + pci_disable_device(pdev); + + /* Move to Low power state*/ + pci_set_power_state(pdev, PCI_D3hot); + + return rv; +} + +/* + * Called for each probed device when the device is resumed. + * + * return value + * 0 Success + * <0 Error + */ +static int mtip_pci_resume(struct pci_dev *pdev) +{ + int rv = 0; + struct driver_data *dd; + + dd = pci_get_drvdata(pdev); + if (!dd) { + dev_err(&pdev->dev, + "Driver private datastructure is NULL\n"); + return -EFAULT; + } + + /* Move the device to active State */ + pci_set_power_state(pdev, PCI_D0); + + /* Restore PCI configuration space */ + pci_restore_state(pdev); + + /* Enable the PCI device*/ + rv = pcim_enable_device(pdev); + if (rv < 0) { + dev_err(&pdev->dev, + "Failed to enable card during resume\n"); + goto err; + } + pci_set_master(pdev); + + /* + * Calls hbaReset, initPort, & startPort function + * then enables interrupts + */ + rv = mtip_block_resume(dd); + if (rv < 0) + dev_err(&pdev->dev, "Unable to resume\n"); + +err: + atomic_set(&dd->resumeflag, false); + + return rv; +} + +/* + * Shutdown routine + * + * return value + * None + */ +static void mtip_pci_shutdown(struct pci_dev *pdev) +{ + struct driver_data *dd = pci_get_drvdata(pdev); + if (dd) + mtip_block_shutdown(dd); +} + +/* Table of device ids supported by this driver. */ +static DEFINE_PCI_DEVICE_TABLE(mtip_pci_tbl) = { + { PCI_DEVICE(PCI_VENDOR_ID_MICRON, P320_DEVICE_ID) }, + { 0 } +}; + +/* Structure that describes the PCI driver functions. */ +static struct pci_driver mtip_pci_driver = { + .name = MTIP_DRV_NAME, + .id_table = mtip_pci_tbl, + .probe = mtip_pci_probe, + .remove = mtip_pci_remove, + .suspend = mtip_pci_suspend, + .resume = mtip_pci_resume, + .shutdown = mtip_pci_shutdown, +}; + +MODULE_DEVICE_TABLE(pci, mtip_pci_tbl); + +/* + * Module initialization function. + * + * Called once when the module is loaded. This function allocates a major + * block device number to the Cyclone devices and registers the PCI layer + * of the driver. + * + * Return value + * 0 on success else error code. + */ +static int __init mtip_init(void) +{ + printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n"); + + /* Allocate a major block device number to use with this driver. */ + mtip_major = register_blkdev(0, MTIP_DRV_NAME); + if (mtip_major < 0) { + printk(KERN_ERR "Unable to register block device (%d)\n", + mtip_major); + return -EBUSY; + } + + /* Register our PCI operations. */ + return pci_register_driver(&mtip_pci_driver); +} + +/* + * Module de-initialization function. + * + * Called once when the module is unloaded. This function deallocates + * the major block device number allocated by mtip_init() and + * unregisters the PCI layer of the driver. + * + * Return value + * none + */ +static void __exit mtip_exit(void) +{ + /* Release the allocated major block device number. */ + unregister_blkdev(mtip_major, MTIP_DRV_NAME); + + /* Unregister the PCI driver. */ + pci_unregister_driver(&mtip_pci_driver); +} + +MODULE_AUTHOR("Micron Technology, Inc"); +MODULE_DESCRIPTION("Micron RealSSD PCIe Block Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MTIP_DRV_VERSION); + +module_init(mtip_init); +module_exit(mtip_exit); diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h new file mode 100644 index 000000000000..723d7c4946dc --- /dev/null +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -0,0 +1,423 @@ +/* + * mtip32xx.h - Header file for the P320 SSD Block Driver + * Copyright (C) 2011 Micron Technology, Inc. + * + * Portions of this code were derived from works subjected to the + * following copyright: + * Copyright (C) 2009 Integrated Device Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 __MTIP32XX_H__ +#define __MTIP32XX_H__ + +#include <linux/spinlock.h> +#include <linux/rwsem.h> +#include <linux/ata.h> +#include <linux/interrupt.h> +#include <linux/genhd.h> +#include <linux/version.h> + +/* Offset of Subsystem Device ID in pci confoguration space */ +#define PCI_SUBSYSTEM_DEVICEID 0x2E + +/* offset of Device Control register in PCIe extended capabilites space */ +#define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 + +/* # of times to retry timed out IOs */ +#define MTIP_MAX_RETRIES 5 + +/* Various timeout values in ms */ +#define MTIP_NCQ_COMMAND_TIMEOUT_MS 5000 +#define MTIP_IOCTL_COMMAND_TIMEOUT_MS 5000 +#define MTIP_INTERNAL_COMMAND_TIMEOUT_MS 5000 + +/* check for timeouts every 500ms */ +#define MTIP_TIMEOUT_CHECK_PERIOD 500 + +/* ftl rebuild */ +#define MTIP_FTL_REBUILD_OFFSET 142 +#define MTIP_FTL_REBUILD_MAGIC 0xED51 +#define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000 + +/* Macro to extract the tag bit number from a tag value. */ +#define MTIP_TAG_BIT(tag) (tag & 0x1F) + +/* + * Macro to extract the tag index from a tag value. The index + * is used to access the correct s_active/Command Issue register based + * on the tag value. + */ +#define MTIP_TAG_INDEX(tag) (tag >> 5) + +/* + * Maximum number of scatter gather entries + * a single command may have. + */ +#define MTIP_MAX_SG 128 + +/* + * Maximum number of slot groups (Command Issue & s_active registers) + * NOTE: This is the driver maximum; check dd->slot_groups for actual value. + */ +#define MTIP_MAX_SLOT_GROUPS 8 + +/* Internal command tag. */ +#define MTIP_TAG_INTERNAL 0 + +/* Micron Vendor ID & P320x SSD Device ID */ +#define PCI_VENDOR_ID_MICRON 0x1344 +#define P320_DEVICE_ID 0x5150 + +/* Driver name and version strings */ +#define MTIP_DRV_NAME "mtip32xx" +#define MTIP_DRV_VERSION "1.2.6os3" + +/* Maximum number of minor device numbers per device. */ +#define MTIP_MAX_MINORS 16 + +/* Maximum number of supported command slots. */ +#define MTIP_MAX_COMMAND_SLOTS (MTIP_MAX_SLOT_GROUPS * 32) + +/* + * Per-tag bitfield size in longs. + * Linux bit manipulation functions + * (i.e. test_and_set_bit, find_next_zero_bit) + * manipulate memory in longs, so we try to make the math work. + * take the slot groups and find the number of longs, rounding up. + * Careful! i386 and x86_64 use different size longs! + */ +#define U32_PER_LONG (sizeof(long) / sizeof(u32)) +#define SLOTBITS_IN_LONGS ((MTIP_MAX_SLOT_GROUPS + \ + (U32_PER_LONG-1))/U32_PER_LONG) + +/* BAR number used to access the HBA registers. */ +#define MTIP_ABAR 5 + +/* Forced Unit Access Bit */ +#define FUA_BIT 0x80 + +#ifdef DEBUG + #define dbg_printk(format, arg...) \ + printk(pr_fmt(format), ##arg); +#else + #define dbg_printk(format, arg...) +#endif + +#define __force_bit2int (unsigned int __force) + +/* below are bit numbers in 'flags' defined in mtip_port */ +#define MTIP_FLAG_IC_ACTIVE_BIT 0 +#define MTIP_FLAG_EH_ACTIVE_BIT 1 +#define MTIP_FLAG_SVC_THD_ACTIVE_BIT 2 +#define MTIP_FLAG_ISSUE_CMDS_BIT 4 +#define MTIP_FLAG_REBUILD_BIT 5 +#define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT 8 + +/* Register Frame Information Structure (FIS), host to device. */ +struct host_to_dev_fis { + /* + * FIS type. + * - 27h Register FIS, host to device. + * - 34h Register FIS, device to host. + * - 39h DMA Activate FIS, device to host. + * - 41h DMA Setup FIS, bi-directional. + * - 46h Data FIS, bi-directional. + * - 58h BIST Activate FIS, bi-directional. + * - 5Fh PIO Setup FIS, device to host. + * - A1h Set Device Bits FIS, device to host. + */ + unsigned char type; + unsigned char opts; + unsigned char command; + unsigned char features; + + union { + unsigned char lba_low; + unsigned char sector; + }; + union { + unsigned char lba_mid; + unsigned char cyl_low; + }; + union { + unsigned char lba_hi; + unsigned char cyl_hi; + }; + union { + unsigned char device; + unsigned char head; + }; + + union { + unsigned char lba_low_ex; + unsigned char sector_ex; + }; + union { + unsigned char lba_mid_ex; + unsigned char cyl_low_ex; + }; + union { + unsigned char lba_hi_ex; + unsigned char cyl_hi_ex; + }; + unsigned char features_ex; + + unsigned char sect_count; + unsigned char sect_cnt_ex; + unsigned char res2; + unsigned char control; + + unsigned int res3; +}; + +/* Command header structure. */ +struct mtip_cmd_hdr { + /* + * Command options. + * - Bits 31:16 Number of PRD entries. + * - Bits 15:8 Unused in this implementation. + * - Bit 7 Prefetch bit, informs the drive to prefetch PRD entries. + * - Bit 6 Write bit, should be set when writing data to the device. + * - Bit 5 Unused in this implementation. + * - Bits 4:0 Length of the command FIS in DWords (DWord = 4 bytes). + */ + unsigned int opts; + /* This field is unsed when using NCQ. */ + union { + unsigned int byte_count; + unsigned int status; + }; + /* + * Lower 32 bits of the command table address associated with this + * header. The command table addresses must be 128 byte aligned. + */ + unsigned int ctba; + /* + * If 64 bit addressing is used this field is the upper 32 bits + * of the command table address associated with this command. + */ + unsigned int ctbau; + /* Reserved and unused. */ + unsigned int res[4]; +}; + +/* Command scatter gather structure (PRD). */ +struct mtip_cmd_sg { + /* + * Low 32 bits of the data buffer address. For P320 this + * address must be 8 byte aligned signified by bits 2:0 being + * set to 0. + */ + unsigned int dba; + /* + * When 64 bit addressing is used this field is the upper + * 32 bits of the data buffer address. + */ + unsigned int dba_upper; + /* Unused. */ + unsigned int reserved; + /* + * Bit 31: interrupt when this data block has been transferred. + * Bits 30..22: reserved + * Bits 21..0: byte count (minus 1). For P320 the byte count must be + * 8 byte aligned signified by bits 2:0 being set to 1. + */ + unsigned int info; +}; +struct mtip_port; + +/* Structure used to describe a command. */ +struct mtip_cmd { + + struct mtip_cmd_hdr *command_header; /* ptr to command header entry */ + + dma_addr_t command_header_dma; /* corresponding physical address */ + + void *command; /* ptr to command table entry */ + + dma_addr_t command_dma; /* corresponding physical address */ + + void *comp_data; /* data passed to completion function comp_func() */ + /* + * Completion function called by the ISR upon completion of + * a command. + */ + void (*comp_func)(struct mtip_port *port, + int tag, + void *data, + int status); + /* Additional callback function that may be called by comp_func() */ + void (*async_callback)(void *data, int status); + + void *async_data; /* Addl. data passed to async_callback() */ + + int scatter_ents; /* Number of scatter list entries used */ + + struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */ + + int retries; /* The number of retries left for this command. */ + + int direction; /* Data transfer direction */ + + unsigned long comp_time; /* command completion time, in jiffies */ + + atomic_t active; /* declares if this command sent to the drive. */ +}; + +/* Structure used to describe a port. */ +struct mtip_port { + /* Pointer back to the driver data for this port. */ + struct driver_data *dd; + /* + * Used to determine if the data pointed to by the + * identify field is valid. + */ + unsigned long identify_valid; + /* Base address of the memory mapped IO for the port. */ + void __iomem *mmio; + /* Array of pointers to the memory mapped s_active registers. */ + void __iomem *s_active[MTIP_MAX_SLOT_GROUPS]; + /* Array of pointers to the memory mapped completed registers. */ + void __iomem *completed[MTIP_MAX_SLOT_GROUPS]; + /* Array of pointers to the memory mapped Command Issue registers. */ + void __iomem *cmd_issue[MTIP_MAX_SLOT_GROUPS]; + /* + * Pointer to the beginning of the command header memory as used + * by the driver. + */ + void *command_list; + /* + * Pointer to the beginning of the command header memory as used + * by the DMA. + */ + dma_addr_t command_list_dma; + /* + * Pointer to the beginning of the RX FIS memory as used + * by the driver. + */ + void *rxfis; + /* + * Pointer to the beginning of the RX FIS memory as used + * by the DMA. + */ + dma_addr_t rxfis_dma; + /* + * Pointer to the beginning of the command table memory as used + * by the driver. + */ + void *command_table; + /* + * Pointer to the beginning of the command table memory as used + * by the DMA. + */ + dma_addr_t command_tbl_dma; + /* + * Pointer to the beginning of the identify data memory as used + * by the driver. + */ + u16 *identify; + /* + * Pointer to the beginning of the identify data memory as used + * by the DMA. + */ + dma_addr_t identify_dma; + /* + * Pointer to the beginning of a sector buffer that is used + * by the driver when issuing internal commands. + */ + u16 *sector_buffer; + /* + * Pointer to the beginning of a sector buffer that is used + * by the DMA when the driver issues internal commands. + */ + dma_addr_t sector_buffer_dma; + /* + * Bit significant, used to determine if a command slot has + * been allocated. i.e. the slot is in use. Bits are cleared + * when the command slot and all associated data structures + * are no longer needed. + */ + unsigned long allocated[SLOTBITS_IN_LONGS]; + /* + * used to queue commands when an internal command is in progress + * or error handling is active + */ + unsigned long cmds_to_issue[SLOTBITS_IN_LONGS]; + /* + * Array of command slots. Structure includes pointers to the + * command header and command table, and completion function and data + * pointers. + */ + struct mtip_cmd commands[MTIP_MAX_COMMAND_SLOTS]; + /* Used by mtip_service_thread to wait for an event */ + wait_queue_head_t svc_wait; + /* + * indicates the state of the port. Also, helps the service thread + * to determine its action on wake up. + */ + unsigned long flags; + /* + * Timer used to complete commands that have been active for too long. + */ + struct timer_list cmd_timer; + /* + * Semaphore used to block threads if there are no + * command slots available. + */ + struct semaphore cmd_slot; + /* Spinlock for working around command-issue bug. */ + spinlock_t cmd_issue_lock; +}; + +/* + * Driver private data structure. + * + * One structure is allocated per probed device. + */ +struct driver_data { + void __iomem *mmio; /* Base address of the HBA registers. */ + + int major; /* Major device number. */ + + int instance; /* Instance number. First device probed is 0, ... */ + + struct gendisk *disk; /* Pointer to our gendisk structure. */ + + struct pci_dev *pdev; /* Pointer to the PCI device structure. */ + + struct request_queue *queue; /* Our request queue. */ + + struct mtip_port *port; /* Pointer to the port data structure. */ + + /* Tasklet used to process the bottom half of the ISR. */ + struct tasklet_struct tasklet; + + unsigned product_type; /* magic value declaring the product type */ + + unsigned slot_groups; /* number of slot groups the product supports */ + + atomic_t drv_cleanup_done; /* Atomic variable for SRSI */ + + unsigned long index; /* Index to determine the disk name */ + + unsigned int ftlrebuildflag; /* FTL rebuild flag */ + + atomic_t resumeflag; /* Atomic variable to track suspend/resume */ + + atomic_t eh_active; /* Flag for error handling tracking */ + + struct task_struct *mtip_svc_handler; /* task_struct of svc thd */ +}; + +#endif diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c index ad124525ac23..ec64e7f5d1ce 100644 --- a/drivers/block/paride/bpck6.c +++ b/drivers/block/paride/bpck6.c @@ -20,9 +20,6 @@ */ -/* PARAMETERS */ -static int verbose; /* set this to 1 to see debugging messages and whatnot */ - #define BACKPACK_VERSION "2.0.2" #include <linux/module.h> @@ -36,6 +33,8 @@ static int verbose; /* set this to 1 to see debugging messages and whatnot */ #include "ppc6lnx.c" #include "paride.h" +/* PARAMETERS */ +static bool verbose; /* set this to 1 to see debugging messages and whatnot */ #define PPCSTRUCT(pi) ((Interface *)(pi->private)) diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 46b8136c31bb..ba2b6b5e5910 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -144,7 +144,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; static DEFINE_MUTEX(pcd_mutex); static DEFINE_SPINLOCK(pcd_lock); -module_param(verbose, bool, 0644); +module_param(verbose, int, 0644); module_param(major, int, 0); module_param(name, charp, 0); module_param(nice, int, 0); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 869e7676d46f..831e3ac156e6 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -124,8 +124,9 @@ by default. */ +#include <linux/types.h> -static int verbose = 0; +static bool verbose = 0; static int major = PD_MAJOR; static char *name = PD_NAME; static int cluster = 64; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index f21b520ef419..ec8f9ed6326e 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -118,13 +118,15 @@ #define PF_NAME "pf" #define PF_UNITS 4 +#include <linux/types.h> + /* Here are things one can override from the insmod command. Most are autoprobed by paride unless set here. Verbose is off by default. */ -static int verbose = 0; +static bool verbose = 0; static int major = PF_MAJOR; static char *name = PF_NAME; static int cluster = 64; diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index a79fb4f7ff62..4a27b1de5fcb 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -130,13 +130,14 @@ #define PI_PG 4 #endif +#include <linux/types.h> /* Here are things one can override from the insmod command. Most are autoprobed by paride unless set here. Verbose is 0 by default. */ -static int verbose = 0; +static bool verbose = 0; static int major = PG_MAJOR; static char *name = PG_NAME; static int disable = 0; diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 7179f79d7468..2596042eb987 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -109,13 +109,15 @@ #define PT_NAME "pt" #define PT_UNITS 4 +#include <linux/types.h> + /* Here are things one can override from the insmod command. Most are autoprobed by paride unless set here. Verbose is on by default. */ -static int verbose = 0; +static bool verbose = 0; static int major = PT_MAJOR; static char *name = PT_NAME; static int disable = 0; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 148ab944378d..3fd31dec8c9c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -2184,6 +2184,8 @@ static ssize_t rbd_add(struct bus_type *bus, INIT_LIST_HEAD(&rbd_dev->node); INIT_LIST_HEAD(&rbd_dev->snaps); + init_rwsem(&rbd_dev->header.snap_rwsem); + /* generate unique id: find highest unique id, add one */ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index b70f0fca9a42..e7472f567c9d 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -619,8 +619,10 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx) host->state == HST_DEV_SCAN); spin_unlock_irq(&host->lock); - DPRINTK("blk_insert_request, tag == %u\n", idx); - blk_insert_request(host->oob_q, crq->rq, 1, crq); + DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx); + crq->rq->cmd_type = REQ_TYPE_SPECIAL; + crq->rq->special = crq; + blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL); return 0; @@ -658,8 +660,10 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func) BUG_ON(rc < 0); crq->msg_bucket = (u32) rc; - DPRINTK("blk_insert_request, tag == %u\n", idx); - blk_insert_request(host->oob_q, crq->rq, 1, crq); + DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx); + crq->rq->cmd_type = REQ_TYPE_SPECIAL; + crq->rq->special = crq; + blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL); return 0; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 0e376d46bdd1..7333b9e44411 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1744,12 +1744,11 @@ static int ub_bd_release(struct gendisk *disk, fmode_t mode) static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = bdev->bd_disk; void __user *usermem = (void __user *) arg; int ret; mutex_lock(&ub_mutex); - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem); + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem); mutex_unlock(&ub_mutex); return ret; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index ffd5ca919295..c4a60badf252 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -250,8 +250,8 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) return -ENOTTY; - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, - (void __user *)data); + return scsi_cmd_blk_ioctl(bdev, mode, cmd, + (void __user *)data); } /* We provide getgeo only to please some old bootloader/partitioning tools */ diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 4abd2bcd20fb..51a972704db5 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -148,7 +148,7 @@ static volatile int xdc_busy; static struct timer_list xd_watchdog_int; static volatile u_char xd_error; -static int nodma = XD_DONT_USE_DMA; +static bool nodma = XD_DONT_USE_DMA; static struct request_queue *xd_queue; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 15ec4db194d1..0088bf60f368 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -39,9 +39,6 @@ #include <linux/list.h> #include <linux/delay.h> #include <linux/freezer.h> -#include <linux/loop.h> -#include <linux/falloc.h> -#include <linux/fs.h> #include <xen/events.h> #include <xen/page.h> @@ -362,7 +359,7 @@ static int xen_blkbk_map(struct blkif_request *req, { struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST]; int i; - int nseg = req->nr_segments; + int nseg = req->u.rw.nr_segments; int ret = 0; /* @@ -416,30 +413,25 @@ static int xen_blkbk_map(struct blkif_request *req, return ret; } -static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req) +static int dispatch_discard_io(struct xen_blkif *blkif, + struct blkif_request *req) { int err = 0; int status = BLKIF_RSP_OKAY; struct block_device *bdev = blkif->vbd.bdev; - if (blkif->blk_backend_type == BLKIF_BACKEND_PHY) - /* just forward the discard request */ + blkif->st_ds_req++; + + xen_blkif_get(blkif); + if (blkif->blk_backend_type == BLKIF_BACKEND_PHY || + blkif->blk_backend_type == BLKIF_BACKEND_FILE) { + unsigned long secure = (blkif->vbd.discard_secure && + (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? + BLKDEV_DISCARD_SECURE : 0; err = blkdev_issue_discard(bdev, req->u.discard.sector_number, req->u.discard.nr_sectors, - GFP_KERNEL, 0); - else if (blkif->blk_backend_type == BLKIF_BACKEND_FILE) { - /* punch a hole in the backing file */ - struct loop_device *lo = bdev->bd_disk->private_data; - struct file *file = lo->lo_backing_file; - - if (file->f_op->fallocate) - err = file->f_op->fallocate(file, - FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, - req->u.discard.sector_number << 9, - req->u.discard.nr_sectors << 9); - else - err = -EOPNOTSUPP; + GFP_KERNEL, secure); } else err = -EOPNOTSUPP; @@ -449,7 +441,9 @@ static void xen_blk_discard(struct xen_blkif *blkif, struct blkif_request *req) } else if (err) status = BLKIF_RSP_ERROR; - make_response(blkif, req->id, req->operation, status); + make_response(blkif, req->u.discard.id, req->operation, status); + xen_blkif_put(blkif); + return err; } static void xen_blk_drain_io(struct xen_blkif *blkif) @@ -573,8 +567,11 @@ __do_block_io_op(struct xen_blkif *blkif) /* Apply all sanity checks to /private copy/ of request. */ barrier(); - - if (dispatch_rw_block_io(blkif, &req, pending_req)) + if (unlikely(req.operation == BLKIF_OP_DISCARD)) { + free_req(pending_req); + if (dispatch_discard_io(blkif, &req)) + break; + } else if (dispatch_rw_block_io(blkif, &req, pending_req)) break; /* Yield point for this unbounded loop. */ @@ -633,10 +630,6 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, blkif->st_f_req++; operation = WRITE_FLUSH; break; - case BLKIF_OP_DISCARD: - blkif->st_ds_req++; - operation = REQ_DISCARD; - break; default: operation = 0; /* make gcc happy */ goto fail_response; @@ -644,9 +637,9 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, } /* Check that the number of segments is sane. */ - nseg = req->nr_segments; - if (unlikely(nseg == 0 && operation != WRITE_FLUSH && - operation != REQ_DISCARD) || + nseg = req->u.rw.nr_segments; + + if (unlikely(nseg == 0 && operation != WRITE_FLUSH) || unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { pr_debug(DRV_PFX "Bad number of segments in request (%d)\n", nseg); @@ -654,12 +647,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, goto fail_response; } - preq.dev = req->handle; + preq.dev = req->u.rw.handle; preq.sector_number = req->u.rw.sector_number; preq.nr_sects = 0; pending_req->blkif = blkif; - pending_req->id = req->id; + pending_req->id = req->u.rw.id; pending_req->operation = req->operation; pending_req->status = BLKIF_RSP_OKAY; pending_req->nr_pages = nseg; @@ -707,7 +700,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, * the hypercall to unmap the grants - that is all done in * xen_blkbk_unmap. */ - if (operation != REQ_DISCARD && xen_blkbk_map(req, pending_req, seg)) + if (xen_blkbk_map(req, pending_req, seg)) goto fail_flush; /* @@ -739,23 +732,16 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, /* This will be hit if the operation was a flush or discard. */ if (!bio) { - BUG_ON(operation != WRITE_FLUSH && operation != REQ_DISCARD); + BUG_ON(operation != WRITE_FLUSH); - if (operation == WRITE_FLUSH) { - bio = bio_alloc(GFP_KERNEL, 0); - if (unlikely(bio == NULL)) - goto fail_put_bio; + bio = bio_alloc(GFP_KERNEL, 0); + if (unlikely(bio == NULL)) + goto fail_put_bio; - biolist[nbio++] = bio; - bio->bi_bdev = preq.bdev; - bio->bi_private = pending_req; - bio->bi_end_io = end_block_io_op; - } else if (operation == REQ_DISCARD) { - xen_blk_discard(blkif, req); - xen_blkif_put(blkif); - free_req(pending_req); - return 0; - } + biolist[nbio++] = bio; + bio->bi_bdev = preq.bdev; + bio->bi_private = pending_req; + bio->bi_end_io = end_block_io_op; } /* @@ -784,7 +770,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, xen_blkbk_unmap(pending_req); fail_response: /* Haven't submitted any bio's yet. */ - make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); + make_response(blkif, req->u.rw.id, req->operation, BLKIF_RSP_ERROR); free_req(pending_req); msleep(1); /* back off a bit */ return -EIO; diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index dfb1b3a43a5d..d0ee7edc9be8 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -60,58 +60,66 @@ struct blkif_common_response { char dummy; }; -/* i386 protocol version */ -#pragma pack(push, 4) - struct blkif_x86_32_request_rw { + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; +} __attribute__((__packed__)); struct blkif_x86_32_request_discard { + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero */ + blkif_vdev_t _pad1; /* was "handle" for read/write requests */ + uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - uint64_t nr_sectors; -}; + uint64_t nr_sectors; +} __attribute__((__packed__)); struct blkif_x86_32_request { uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t id; /* private guest value, echoed in resp */ union { struct blkif_x86_32_request_rw rw; struct blkif_x86_32_request_discard discard; } u; -}; +} __attribute__((__packed__)); + +/* i386 protocol version */ +#pragma pack(push, 4) struct blkif_x86_32_response { uint64_t id; /* copied from request */ uint8_t operation; /* copied from request */ int16_t status; /* BLKIF_RSP_??? */ }; #pragma pack(pop) - /* x86_64 protocol version */ struct blkif_x86_64_request_rw { + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint32_t _pad1; /* offsetof(blkif_reqest..,u.rw.id)==8 */ + uint64_t id; blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; +} __attribute__((__packed__)); struct blkif_x86_64_request_discard { + uint8_t flag; /* BLKIF_DISCARD_SECURE or zero */ + blkif_vdev_t _pad1; /* was "handle" for read/write requests */ + uint32_t _pad2; /* offsetof(blkif_..,u.discard.id)==8 */ + uint64_t id; blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - uint64_t nr_sectors; -}; + uint64_t nr_sectors; +} __attribute__((__packed__)); struct blkif_x86_64_request { uint8_t operation; /* BLKIF_OP_??? */ - uint8_t nr_segments; /* number of segments */ - blkif_vdev_t handle; /* only for read/write requests */ - uint64_t __attribute__((__aligned__(8))) id; union { struct blkif_x86_64_request_rw rw; struct blkif_x86_64_request_discard discard; } u; -}; +} __attribute__((__packed__)); + struct blkif_x86_64_response { uint64_t __attribute__((__aligned__(8))) id; uint8_t operation; /* copied from request */ @@ -156,6 +164,7 @@ struct xen_vbd { /* Cached size parameter. */ sector_t size; bool flush_support; + bool discard_secure; }; struct backend_info; @@ -237,22 +246,23 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst, { int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; dst->operation = src->operation; - dst->nr_segments = src->nr_segments; - dst->handle = src->handle; - dst->id = src->id; switch (src->operation) { case BLKIF_OP_READ: case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = src->u.rw.nr_segments; + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; dst->u.rw.sector_number = src->u.rw.sector_number; barrier(); - if (n > dst->nr_segments) - n = dst->nr_segments; + if (n > dst->u.rw.nr_segments) + n = dst->u.rw.nr_segments; for (i = 0; i < n; i++) dst->u.rw.seg[i] = src->u.rw.seg[i]; break; case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; @@ -266,22 +276,23 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst, { int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST; dst->operation = src->operation; - dst->nr_segments = src->nr_segments; - dst->handle = src->handle; - dst->id = src->id; switch (src->operation) { case BLKIF_OP_READ: case BLKIF_OP_WRITE: case BLKIF_OP_WRITE_BARRIER: case BLKIF_OP_FLUSH_DISKCACHE: + dst->u.rw.nr_segments = src->u.rw.nr_segments; + dst->u.rw.handle = src->u.rw.handle; + dst->u.rw.id = src->u.rw.id; dst->u.rw.sector_number = src->u.rw.sector_number; barrier(); - if (n > dst->nr_segments) - n = dst->nr_segments; + if (n > dst->u.rw.nr_segments) + n = dst->u.rw.nr_segments; for (i = 0; i < n; i++) dst->u.rw.seg[i] = src->u.rw.seg[i]; break; case BLKIF_OP_DISCARD: + dst->u.discard.flag = src->u.discard.flag; dst->u.discard.sector_number = src->u.discard.sector_number; dst->u.discard.nr_sectors = src->u.discard.nr_sectors; break; diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 37c794d31264..24a2fb57e5d0 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -338,6 +338,9 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, if (q && q->flush_flags) vbd->flush_support = true; + if (q && blk_queue_secdiscard(q)) + vbd->discard_secure = true; + DPRINTK("Successful creation of handle=%04x (dom=%u)\n", handle, blkif->domid); return 0; @@ -420,6 +423,15 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) state = 1; blkif->blk_backend_type = BLKIF_BACKEND_PHY; } + /* Optional. */ + err = xenbus_printf(xbt, dev->nodename, + "discard-secure", "%d", + blkif->vbd.discard_secure); + if (err) { + xenbus_dev_fatal(dev, err, + "writting discard-secure"); + goto kfree; + } } } else { err = PTR_ERR(type); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 9fd3ee203b1e..2f22874c0a37 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -98,7 +98,8 @@ struct blkfront_info unsigned long shadow_free; unsigned int feature_flush; unsigned int flush_op; - unsigned int feature_discard; + unsigned int feature_discard:1; + unsigned int feature_secdiscard:1; unsigned int discard_granularity; unsigned int discard_alignment; int is_ready; @@ -135,15 +136,15 @@ static int get_id_from_freelist(struct blkfront_info *info) { unsigned long free = info->shadow_free; BUG_ON(free >= BLK_RING_SIZE); - info->shadow_free = info->shadow[free].req.id; - info->shadow[free].req.id = 0x0fffffee; /* debug */ + info->shadow_free = info->shadow[free].req.u.rw.id; + info->shadow[free].req.u.rw.id = 0x0fffffee; /* debug */ return free; } static void add_id_to_freelist(struct blkfront_info *info, unsigned long id) { - info->shadow[id].req.id = info->shadow_free; + info->shadow[id].req.u.rw.id = info->shadow_free; info->shadow[id].request = NULL; info->shadow_free = id; } @@ -156,7 +157,7 @@ static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) if (end > nr_minors) { unsigned long *bitmap, *old; - bitmap = kzalloc(BITS_TO_LONGS(end) * sizeof(*bitmap), + bitmap = kcalloc(BITS_TO_LONGS(end), sizeof(*bitmap), GFP_KERNEL); if (bitmap == NULL) return -ENOMEM; @@ -287,9 +288,9 @@ static int blkif_queue_request(struct request *req) id = get_id_from_freelist(info); info->shadow[id].request = req; - ring_req->id = id; + ring_req->u.rw.id = id; ring_req->u.rw.sector_number = (blkif_sector_t)blk_rq_pos(req); - ring_req->handle = info->handle; + ring_req->u.rw.handle = info->handle; ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : BLKIF_OP_READ; @@ -305,16 +306,21 @@ static int blkif_queue_request(struct request *req) ring_req->operation = info->flush_op; } - if (unlikely(req->cmd_flags & REQ_DISCARD)) { + if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) { /* id, sector_number and handle are set above. */ ring_req->operation = BLKIF_OP_DISCARD; - ring_req->nr_segments = 0; ring_req->u.discard.nr_sectors = blk_rq_sectors(req); + if ((req->cmd_flags & REQ_SECURE) && info->feature_secdiscard) + ring_req->u.discard.flag = BLKIF_DISCARD_SECURE; + else + ring_req->u.discard.flag = 0; } else { - ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg); - BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST); + ring_req->u.rw.nr_segments = blk_rq_map_sg(req->q, req, + info->sg); + BUG_ON(ring_req->u.rw.nr_segments > + BLKIF_MAX_SEGMENTS_PER_REQUEST); - for_each_sg(info->sg, sg, ring_req->nr_segments, i) { + for_each_sg(info->sg, sg, ring_req->u.rw.nr_segments, i) { buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg))); fsect = sg->offset >> 9; lsect = fsect + (sg->length >> 9) - 1; @@ -424,6 +430,8 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) blk_queue_max_discard_sectors(rq, get_capacity(gd)); rq->limits.discard_granularity = info->discard_granularity; rq->limits.discard_alignment = info->discard_alignment; + if (info->feature_secdiscard) + queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, rq); } /* Hard sector size and max sectors impersonate the equiv. hardware. */ @@ -705,7 +713,9 @@ static void blkif_free(struct blkfront_info *info, int suspend) static void blkif_completion(struct blk_shadow *s) { int i; - for (i = 0; i < s->req.nr_segments; i++) + /* Do not let BLKIF_OP_DISCARD as nr_segment is in the same place + * flag. */ + for (i = 0; i < s->req.u.rw.nr_segments; i++) gnttab_end_foreign_access(s->req.u.rw.seg[i].gref, 0, 0UL); } @@ -736,7 +746,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) id = bret->id; req = info->shadow[id].request; - blkif_completion(&info->shadow[id]); + if (bret->operation != BLKIF_OP_DISCARD) + blkif_completion(&info->shadow[id]); add_id_to_freelist(info, id); @@ -749,7 +760,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) info->gd->disk_name); error = -EOPNOTSUPP; info->feature_discard = 0; + info->feature_secdiscard = 0; queue_flag_clear(QUEUE_FLAG_DISCARD, rq); + queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq); } __blk_end_request_all(req, error); break; @@ -763,7 +776,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) error = -EOPNOTSUPP; } if (unlikely(bret->status == BLKIF_RSP_ERROR && - info->shadow[id].req.nr_segments == 0)) { + info->shadow[id].req.u.rw.nr_segments == 0)) { printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n", info->flush_op == BLKIF_OP_WRITE_BARRIER ? "barrier" : "flush disk cache", @@ -984,8 +997,8 @@ static int blkfront_probe(struct xenbus_device *dev, INIT_WORK(&info->work, blkif_restart_queue); for (i = 0; i < BLK_RING_SIZE; i++) - info->shadow[i].req.id = i+1; - info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + info->shadow[i].req.u.rw.id = i+1; + info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff; /* Front end dir is a number, which is used as the id. */ info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0); @@ -1019,9 +1032,9 @@ static int blkif_recover(struct blkfront_info *info) /* Stage 2: Set up free list. */ memset(&info->shadow, 0, sizeof(info->shadow)); for (i = 0; i < BLK_RING_SIZE; i++) - info->shadow[i].req.id = i+1; + info->shadow[i].req.u.rw.id = i+1; info->shadow_free = info->ring.req_prod_pvt; - info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff; /* Stage 3: Find pending requests and requeue them. */ for (i = 0; i < BLK_RING_SIZE; i++) { @@ -1034,17 +1047,19 @@ static int blkif_recover(struct blkfront_info *info) *req = copy[i].req; /* We get a new request id, and must reset the shadow state. */ - req->id = get_id_from_freelist(info); - memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); + req->u.rw.id = get_id_from_freelist(info); + memcpy(&info->shadow[req->u.rw.id], ©[i], sizeof(copy[i])); + if (req->operation != BLKIF_OP_DISCARD) { /* Rewrite any grant references invalidated by susp/resume. */ - for (j = 0; j < req->nr_segments; j++) - gnttab_grant_foreign_access_ref( - req->u.rw.seg[j].gref, - info->xbdev->otherend_id, - pfn_to_mfn(info->shadow[req->id].frame[j]), - rq_data_dir(info->shadow[req->id].request)); - info->shadow[req->id].req = *req; + for (j = 0; j < req->u.rw.nr_segments; j++) + gnttab_grant_foreign_access_ref( + req->u.rw.seg[j].gref, + info->xbdev->otherend_id, + pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]), + rq_data_dir(info->shadow[req->u.rw.id].request)); + } + info->shadow[req->u.rw.id].req = *req; info->ring.req_prod_pvt++; } @@ -1135,11 +1150,13 @@ static void blkfront_setup_discard(struct blkfront_info *info) char *type; unsigned int discard_granularity; unsigned int discard_alignment; + unsigned int discard_secure; type = xenbus_read(XBT_NIL, info->xbdev->otherend, "type", NULL); if (IS_ERR(type)) return; + info->feature_secdiscard = 0; if (strncmp(type, "phy", 3) == 0) { err = xenbus_gather(XBT_NIL, info->xbdev->otherend, "discard-granularity", "%u", &discard_granularity, @@ -1150,6 +1167,12 @@ static void blkfront_setup_discard(struct blkfront_info *info) info->discard_granularity = discard_granularity; info->discard_alignment = discard_alignment; } + err = xenbus_gather(XBT_NIL, info->xbdev->otherend, + "discard-secure", "%d", &discard_secure, + NULL); + if (!err) + info->feature_secdiscard = discard_secure; + } else if (strncmp(type, "file", 4) == 0) info->feature_discard = 1; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 55ac349695c4..f00f596c1029 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -37,13 +37,13 @@ #define VERSION "0.6" -static int ignore_dga; -static int ignore_csr; -static int ignore_sniffer; -static int disable_scofix; -static int force_scofix; +static bool ignore_dga; +static bool ignore_csr; +static bool ignore_sniffer; +static bool disable_scofix; +static bool force_scofix; -static int reset = 1; +static bool reset = 1; static struct usb_driver btusb_driver; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 9c5b2dc38e29..a767d4de45a4 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -49,8 +49,8 @@ #define VERSION "0.3" -static int txcrc = 1; -static int hciextn = 1; +static bool txcrc = 1; +static bool hciextn = 1; #define BCSP_TXWINSIZE 4 diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 48ad2a7ab080..07114489994f 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -48,7 +48,7 @@ #define VERSION "2.2" -static int reset = 0; +static bool reset = 0; static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 2118211aff99..55eaf474d32c 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -285,17 +285,17 @@ #include <asm/uaccess.h> /* used to tell the module to turn on full debugging messages */ -static int debug; +static bool debug; /* used to keep tray locked at all times */ static int keeplocked; /* default compatibility mode */ -static int autoclose=1; -static int autoeject; -static int lockdoor = 1; +static bool autoclose=1; +static bool autoeject; +static bool lockdoor = 1; /* will we ever get to use this... sigh. */ -static int check_media_type; +static bool check_media_type; /* automatically restart mrw format */ -static int mrw_format_restart = 1; +static bool mrw_format_restart = 1; module_param(debug, bool, 0); module_param(autoclose, bool, 0); module_param(autoeject, bool, 0); @@ -2746,12 +2746,11 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, { void __user *argp = (void __user *)arg; int ret; - struct gendisk *disk = bdev->bd_disk; /* * Try the generic SCSI command ioctl's first. */ - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); if (ret != -ENOTTY) return ret; diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 780498d76581..444f8b6ab411 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -33,7 +33,7 @@ #define ULI_X86_64_ENU_SCR_REG 0x54 static struct resource *aperture_resource; -static int __initdata agp_try_unsupported = 1; +static bool __initdata agp_try_unsupported = 1; static int agp_bridges_found; static void amd64_tlbflush(struct agp_memory *temp) diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 29aacd81de78..08704ae53956 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -17,7 +17,7 @@ #define PCI_DEVICE_ID_SI_662 0x0662 #define PCI_DEVICE_ID_SI_671 0x0671 -static int __devinitdata agp_sis_force_delay = 0; +static bool __devinitdata agp_sis_force_delay = 0; static int __devinitdata agp_sis_agp_spec = -1; static int sis_fetch_size(void) diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 6e40072fbf67..40cc0cf2ded6 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -69,19 +69,19 @@ MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); MODULE_LICENSE("GPL"); -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force loading without checking for supported models"); -static int ignore_dmi; +static bool ignore_dmi; module_param(ignore_dmi, bool, 0); MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); -static int restricted; +static bool restricted; module_param(restricted, bool, 0); MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); -static int power_status; +static bool power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 9397ab49b72e..50fcf9c04569 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1227,7 +1227,7 @@ static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSPACING 1 #define DEFAULT_REGSIZE 1 -static int si_trydefaults = 1; +static bool si_trydefaults = 1; static char *si_type[SI_MAX_PARMS]; #define MAX_SI_TYPE_STR 30 static char si_type_str[MAX_SI_TYPE_STR]; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 97c3edb95ae7..f43485607063 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -829,7 +829,7 @@ static struct console lpcons = { static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; static char *parport[LP_NO]; -static int reset; +static bool reset; module_param_array(parport, charp, NULL, 0); module_param(reset, bool, 0); diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index a12f52400dbc..bf586ae1ee83 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -51,7 +51,7 @@ static int write_block(unsigned long p, const char __user *buf, int count); #define KFLASH_ID 0x89A6 //Intel flash #define KFLASH_ID4 0xB0D4 //Intel flash 4Meg -static int flashdebug; //if set - we will display progress msgs +static bool flashdebug; //if set - we will display progress msgs static int gbWriteEnable; static int gbWriteBase64Enable; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 15781396af25..07f6a5abe372 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -439,7 +439,7 @@ static int mgslpc_device_count = 0; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load=0; +static bool break_on_load=0; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index 7c7f42a1f880..9fec3232b736 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -83,8 +83,7 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, struct timeval timestamp; if (reason != KMSG_DUMP_OOPS && - reason != KMSG_DUMP_PANIC && - reason != KMSG_DUMP_KEXEC) + reason != KMSG_DUMP_PANIC) return; /* Only dump oopses if dump_oops is set */ @@ -126,8 +125,8 @@ static int __init ramoops_probe(struct platform_device *pdev) goto fail3; } - rounddown_pow_of_two(pdata->mem_size); - rounddown_pow_of_two(pdata->record_size); + pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); + pdata->record_size = rounddown_pow_of_two(pdata->record_size); /* Check for the minimum memory size */ if (pdata->mem_size < MIN_MEM_SIZE && @@ -148,14 +147,6 @@ static int __init ramoops_probe(struct platform_device *pdev) cxt->phys_addr = pdata->mem_address; cxt->record_size = pdata->record_size; cxt->dump_oops = pdata->dump_oops; - /* - * Update the module parameter variables as well so they are visible - * through /sys/module/ramoops/parameters/ - */ - mem_size = pdata->mem_size; - mem_address = pdata->mem_address; - record_size = pdata->record_size; - dump_oops = pdata->dump_oops; if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) { pr_err("request mem region failed\n"); @@ -176,6 +167,15 @@ static int __init ramoops_probe(struct platform_device *pdev) goto fail1; } + /* + * Update the module parameter variables as well so they are visible + * through /sys/module/ramoops/parameters/ + */ + mem_size = pdata->mem_size; + mem_address = pdata->mem_address; + record_size = pdata->record_size; + dump_oops = pdata->dump_oops; + return 0; fail1: diff --git a/drivers/char/random.c b/drivers/char/random.c index 85da8740586b..54ca8b23cde3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -387,7 +387,7 @@ static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static struct fasync_struct *fasync; #if 0 -static int debug; +static bool debug; module_param(debug, bool, 0644); #define DEBUG_ENT(fmt, arg...) do { \ if (debug) \ @@ -965,6 +965,7 @@ EXPORT_SYMBOL(get_random_bytes); */ static void init_std_data(struct entropy_store *r) { + int i; ktime_t now; unsigned long flags; @@ -974,6 +975,11 @@ static void init_std_data(struct entropy_store *r) now = ktime_get_real(); mix_pool_bytes(r, &now, sizeof(now)); + for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof flags) { + if (!arch_get_random_long(&flags)) + break; + mix_pool_bytes(r, &flags, sizeof(flags)); + } mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 10cc44ceb5d1..a1748621111b 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -255,7 +255,7 @@ out: return size; } -static int itpm; +static bool itpm; module_param(itpm, bool, 0444); MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)"); @@ -500,7 +500,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) return IRQ_HANDLED; } -static int interrupts = 1; +static bool interrupts = 1; module_param(interrupts, bool, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); @@ -828,7 +828,7 @@ static struct platform_driver tis_drv = { static struct platform_device *pdev; -static int force; +static bool force; module_param(force, bool, 0444); MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry"); static int __init init_tis(void) diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index b153674431f1..e294e1b3616c 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -131,7 +131,7 @@ struct r82600_error_info { u32 eapr; }; -static unsigned int disable_hardware_scrub; +static bool disable_hardware_scrub; static struct edac_pci_ctl_info *r82600_pci; diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 68375bc3aef6..80e95aa3bf14 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -66,7 +66,7 @@ * * Concurrent logins are useful together with cluster filesystems. */ -static int sbp2_param_exclusive_login = 1; +static bool sbp2_param_exclusive_login = 1; module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644); MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " "(default = Y, use N for concurrent initiators)"); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 573532f7553e..37c4bd1cacd5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -138,6 +138,7 @@ config GPIO_MXS config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA + select GENERIC_IRQ_CHIP help Say yes here to support the PrimeCell PL061 GPIO device diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 62e641e79e8f..fa10df604c01 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -2,7 +2,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG -obj-$(CONFIG_GPIOLIB) += gpiolib.o +obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c new file mode 100644 index 000000000000..3dd29399cef5 --- /dev/null +++ b/drivers/gpio/devres.c @@ -0,0 +1,90 @@ +/* + * drivers/gpio/devres.c - managed gpio resources + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This file is based on kernel/irq/devres.c + * + * Copyright (c) 2011 John Crispin <blogic@openwrt.org> + */ + +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/gfp.h> + +static void devm_gpio_release(struct device *dev, void *res) +{ + unsigned *gpio = res; + + gpio_free(*gpio); +} + +static int devm_gpio_match(struct device *dev, void *res, void *data) +{ + unsigned *this = res, *gpio = data; + + return *this == *gpio; +} + +/** + * devm_gpio_request - request a gpio for a managed device + * @dev: device to request the gpio for + * @gpio: gpio to allocate + * @label: the name of the requested gpio + * + * Except for the extra @dev argument, this function takes the + * same arguments and performs the same function as + * gpio_request(). GPIOs requested with this function will be + * automatically freed on driver detach. + * + * If an GPIO allocated with this function needs to be freed + * separately, devm_gpio_free() must be used. + */ + +int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) +{ + unsigned *dr; + int rc; + + dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = gpio_request(gpio, label); + if (rc) { + devres_free(dr); + return rc; + } + + *dr = gpio; + devres_add(dev, dr); + + return 0; +} +EXPORT_SYMBOL(devm_gpio_request); + +/** + * devm_gpio_free - free an interrupt + * @dev: device to free gpio for + * @gpio: gpio to free + * + * Except for the extra @dev argument, this function takes the + * same arguments and performs the same function as gpio_free(). + * This function instead of gpio_free() should be used to manually + * free GPIOs allocated with devm_gpio_request(). + */ +void devm_gpio_free(struct device *dev, unsigned int gpio) +{ + + WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match, + &gpio)); + gpio_free(gpio); +} +EXPORT_SYMBOL(devm_gpio_free); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 8f79c03049f3..77c9cc70fa77 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -12,7 +12,6 @@ #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/module.h> -#include <linux/list.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> @@ -23,6 +22,8 @@ #include <linux/amba/bus.h> #include <linux/amba/pl061.h> #include <linux/slab.h> +#include <linux/pm.h> +#include <asm/mach/irq.h> #define GPIODIR 0x400 #define GPIOIS 0x404 @@ -35,25 +36,33 @@ #define PL061_GPIO_NR 8 -struct pl061_gpio { - /* We use a list of pl061_gpio structs for each trigger IRQ in the main - * interrupts controller of the system. We need this to support systems - * in which more that one PL061s are connected to the same IRQ. The ISR - * interates through this list to find the source of the interrupt. - */ - struct list_head list; +#ifdef CONFIG_PM +struct pl061_context_save_regs { + u8 gpio_data; + u8 gpio_dir; + u8 gpio_is; + u8 gpio_ibe; + u8 gpio_iev; + u8 gpio_ie; +}; +#endif +struct pl061_gpio { /* Each of the two spinlocks protects a different set of hardware * regiters and data structurs. This decouples the code of the IRQ from * the GPIO code. This also makes the case of a GPIO routine call from * the IRQ code simpler. */ spinlock_t lock; /* GPIO registers */ - spinlock_t irq_lock; /* IRQ registers */ void __iomem *base; - unsigned irq_base; + int irq_base; + struct irq_chip_generic *irq_gc; struct gpio_chip gc; + +#ifdef CONFIG_PM + struct pl061_context_save_regs csave_regs; +#endif }; static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) @@ -118,46 +127,16 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - if (chip->irq_base == NO_IRQ) + if (chip->irq_base <= 0) return -EINVAL; return chip->irq_base + offset; } -/* - * PL061 GPIO IRQ - */ -static void pl061_irq_disable(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - int offset = d->irq - chip->irq_base; - unsigned long flags; - u8 gpioie; - - spin_lock_irqsave(&chip->irq_lock, flags); - gpioie = readb(chip->base + GPIOIE); - gpioie &= ~(1 << offset); - writeb(gpioie, chip->base + GPIOIE); - spin_unlock_irqrestore(&chip->irq_lock, flags); -} - -static void pl061_irq_enable(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - int offset = d->irq - chip->irq_base; - unsigned long flags; - u8 gpioie; - - spin_lock_irqsave(&chip->irq_lock, flags); - gpioie = readb(chip->base + GPIOIE); - gpioie |= 1 << offset; - writeb(gpioie, chip->base + GPIOIE); - spin_unlock_irqrestore(&chip->irq_lock, flags); -} - static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = gc->private; int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -165,7 +144,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; - spin_lock_irqsave(&chip->irq_lock, flags); + raw_spin_lock_irqsave(&gc->lock, flags); gpioiev = readb(chip->base + GPIOIEV); @@ -194,49 +173,54 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) writeb(gpioiev, chip->base + GPIOIEV); - spin_unlock_irqrestore(&chip->irq_lock, flags); + raw_spin_unlock_irqrestore(&gc->lock, flags); return 0; } -static struct irq_chip pl061_irqchip = { - .name = "GPIO", - .irq_enable = pl061_irq_enable, - .irq_disable = pl061_irq_disable, - .irq_set_type = pl061_irq_type, -}; - static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { - struct list_head *chip_list = irq_get_handler_data(irq); - struct list_head *ptr; - struct pl061_gpio *chip; - - desc->irq_data.chip->irq_ack(&desc->irq_data); - list_for_each(ptr, chip_list) { - unsigned long pending; - int offset; + unsigned long pending; + int offset; + struct pl061_gpio *chip = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); - chip = list_entry(ptr, struct pl061_gpio, list); - pending = readb(chip->base + GPIOMIS); - writeb(pending, chip->base + GPIOIC); - - if (pending == 0) - continue; + chained_irq_enter(irqchip, desc); + pending = readb(chip->base + GPIOMIS); + writeb(pending, chip->base + GPIOIC); + if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(pl061_to_irq(&chip->gc, offset)); } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + + chained_irq_exit(irqchip, desc); +} + +static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) +{ + struct irq_chip_type *ct; + + chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base, + chip->base, handle_simple_irq); + chip->irq_gc->private = chip; + + ct = chip->irq_gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_set_type = pl061_irq_type; + ct->chip.irq_set_wake = irq_gc_set_wake; + ct->regs.mask = GPIOIE; + + irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR), + IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } static int pl061_probe(struct amba_device *dev, const struct amba_id *id) { struct pl061_platform_data *pdata; struct pl061_gpio *chip; - struct list_head *chip_list; int ret, irq, i; - static DECLARE_BITMAP(init_irq, NR_IRQS); chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -248,7 +232,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->irq_base = pdata->irq_base; } else if (dev->dev.of_node) { chip->gc.base = -1; - chip->irq_base = NO_IRQ; + chip->irq_base = 0; } else { ret = -ENODEV; goto free_mem; @@ -267,8 +251,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } spin_lock_init(&chip->lock); - spin_lock_init(&chip->irq_lock); - INIT_LIST_HEAD(&chip->list); chip->gc.direction_input = pl061_direction_input; chip->gc.direction_output = pl061_direction_output; @@ -288,9 +270,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) * irq_chip support */ - if (chip->irq_base == NO_IRQ) + if (chip->irq_base <= 0) return 0; + pl061_init_gc(chip, chip->irq_base); + writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = dev->irq[0]; if (irq < 0) { @@ -298,18 +282,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) goto iounmap; } irq_set_chained_handler(irq, pl061_irq_handler); - if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ - chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); - if (chip_list == NULL) { - clear_bit(irq, init_irq); - ret = -ENOMEM; - goto iounmap; - } - INIT_LIST_HEAD(chip_list); - irq_set_handler_data(irq, chip_list); - } else - chip_list = irq_get_handler_data(irq); - list_add(&chip->list, chip_list); + irq_set_handler_data(irq, chip); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { @@ -319,13 +292,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) else pl061_direction_input(&chip->gc, i); } - - irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, - handle_simple_irq); - set_irq_flags(i+chip->irq_base, IRQF_VALID); - irq_set_chip_data(i + chip->irq_base, chip); } + amba_set_drvdata(dev, chip); + return 0; iounmap: @@ -338,6 +308,53 @@ free_mem: return ret; } +#ifdef CONFIG_PM +static int pl061_suspend(struct device *dev) +{ + struct pl061_gpio *chip = dev_get_drvdata(dev); + int offset; + + chip->csave_regs.gpio_data = 0; + chip->csave_regs.gpio_dir = readb(chip->base + GPIODIR); + chip->csave_regs.gpio_is = readb(chip->base + GPIOIS); + chip->csave_regs.gpio_ibe = readb(chip->base + GPIOIBE); + chip->csave_regs.gpio_iev = readb(chip->base + GPIOIEV); + chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); + + for (offset = 0; offset < PL061_GPIO_NR; offset++) { + if (chip->csave_regs.gpio_dir & (1 << offset)) + chip->csave_regs.gpio_data |= + pl061_get_value(&chip->gc, offset) << offset; + } + + return 0; +} + +static int pl061_resume(struct device *dev) +{ + struct pl061_gpio *chip = dev_get_drvdata(dev); + int offset; + + for (offset = 0; offset < PL061_GPIO_NR; offset++) { + if (chip->csave_regs.gpio_dir & (1 << offset)) + pl061_direction_output(&chip->gc, offset, + chip->csave_regs.gpio_data & + (1 << offset)); + else + pl061_direction_input(&chip->gc, offset); + } + + writeb(chip->csave_regs.gpio_is, chip->base + GPIOIS); + writeb(chip->csave_regs.gpio_ibe, chip->base + GPIOIBE); + writeb(chip->csave_regs.gpio_iev, chip->base + GPIOIEV); + writeb(chip->csave_regs.gpio_ie, chip->base + GPIOIE); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(pl061_dev_pm_ops, pl061_suspend, pl061_resume); +#endif + static struct amba_id pl061_ids[] = { { .id = 0x00041061, @@ -351,6 +368,9 @@ MODULE_DEVICE_TABLE(amba, pl061_ids); static struct amba_driver pl061_gpio_driver = { .drv = { .name = "pl061_gpio", +#ifdef CONFIG_PM + .pm = &pl061_dev_pm_ops, +#endif }, .id_table = pl061_ids, .probe = pl061_probe, diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index b6c1f6d80649..7eecf69362ee 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -47,12 +47,18 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int return 0; } +static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset); +} + static struct gpio_chip sa1100_gpio_chip = { .label = "gpio", .direction_input = sa1100_direction_input, .direction_output = sa1100_direction_output, .set = sa1100_gpio_set, .get = sa1100_gpio_get, + .to_irq = sa1100_to_irq, .base = 0, .ngpio = GPIO_MAX + 1, }; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 4c980b573328..87a68a896abf 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -65,7 +65,14 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val) u8 reg = stmpe->regs[which] - (offset / 8); u8 mask = 1 << (offset % 8); - stmpe_reg_write(stmpe, reg, mask); + /* + * Some variants have single register for gpio set/clear functionality. + * For them we need to write 0 to clear and 1 to set. + */ + if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB]) + stmpe_set_bits(stmpe, reg, mask, val ? mask : 0); + else + stmpe_reg_write(stmpe, reg, mask); } static int stmpe_gpio_direction_output(struct gpio_chip *chip, @@ -132,6 +139,10 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) return -EINVAL; + /* STMPE801 doesn't have RE and FE registers */ + if (stmpe_gpio->stmpe->partnum == STMPE801) + return 0; + if (type == IRQ_TYPE_EDGE_RISING) stmpe_gpio->regs[REG_RE][regoffset] |= mask; else @@ -165,6 +176,11 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) int i, j; for (i = 0; i < CACHE_NR_REGS; i++) { + /* STMPE801 doesn't have RE and FE registers */ + if ((stmpe->partnum == STMPE801) && + (i != REG_IE)) + continue; + for (j = 0; j < num_banks; j++) { u8 old = stmpe_gpio->oldregs[i][j]; u8 new = stmpe_gpio->regs[i][j]; @@ -241,8 +257,11 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) } stmpe_reg_write(stmpe, statmsbreg + i, status[i]); - stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i, - status[i]); + + /* Edge detect register is not present on 801 */ + if (stmpe->partnum != STMPE801) + stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + + i, status[i]); } return IRQ_HANDLED; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 61044c889f7f..bdc293791590 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -361,14 +361,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "Couldn't request MEM resource\n"); - return -ENODEV; - } - - regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + regs = devm_request_and_ioremap(&pdev->dev, res); if (!regs) { dev_err(&pdev->dev, "Couldn't ioremap regs\n"); return -ENODEV; diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 6d0f10b7569c..c100f3e9c920 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -66,6 +66,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) static int cdv_intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; int max_clock = 0; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -82,6 +83,11 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector, if (mode->hdisplay > 1680 || mode->vdisplay > 1050) return MODE_PANEL; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 50d7cfb51662..de25560e629d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -241,6 +241,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) static int cdv_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -255,14 +256,11 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_INTERLACE) return MODE_NO_INTERLACE; - /* - * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it - * will go beyond the stolen memory size allocated to the framebuffer - */ - if (mode->hdisplay > 1680) - return MODE_PANEL; - if (mode->vdisplay > 1050) - return MODE_PANEL; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 36878a60080d..025d30970cc0 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -506,6 +506,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; if (mode->clock > 165000) return MODE_CLOCK_HIGH; if (mode->clock < 20000) @@ -514,6 +515,11 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 4882b29119e0..88b42971c0fd 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1141,6 +1141,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -1160,6 +1161,11 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, return MODE_PANEL; } + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 525744d593c1..7814a760c164 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -18,12 +18,6 @@ #include <linux/vga_switcheroo.h> -#define NOUVEAU_DSM_SUPPORTED 0x00 -#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00 - -#define NOUVEAU_DSM_ACTIVE 0x01 -#define NOUVEAU_DSM_ACTIVE_QUERY 0x00 - #define NOUVEAU_DSM_LED 0x02 #define NOUVEAU_DSM_LED_STATE 0x00 #define NOUVEAU_DSM_LED_OFF 0x10 @@ -35,6 +29,9 @@ #define NOUVEAU_DSM_POWER_SPEED 0x01 #define NOUVEAU_DSM_POWER_STAMINA 0x02 +#define NOUVEAU_DSM_OPTIMUS_FN 0x1A +#define NOUVEAU_DSM_OPTIMUS_ARGS 0x03000001 + static struct nouveau_dsm_priv { bool dsm_detected; bool optimus_detected; @@ -61,7 +58,8 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t * struct acpi_object_list input; union acpi_object params[4]; union acpi_object *obj; - int err; + int i, err; + char args_buff[4]; input.count = 4; input.pointer = params; @@ -73,7 +71,11 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t * params[2].type = ACPI_TYPE_INTEGER; params[2].integer.value = func; params[3].type = ACPI_TYPE_BUFFER; - params[3].buffer.length = 0; + params[3].buffer.length = 4; + /* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */ + for (i = 0; i < 4; i++) + args_buff[i] = (arg >> i * 8) & 0xFF; + params[3].buffer.pointer = args_buff; err = acpi_evaluate_object(handle, "_DSM", &input, &output); if (err) { @@ -148,6 +150,23 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) return 0; } +/* Returns 1 if a DSM function is usable and 0 otherwise */ +static int nouveau_test_dsm(acpi_handle test_handle, + int (*dsm_func)(acpi_handle, int, int, uint32_t *), + int sfnc) +{ + u32 result = 0; + + /* Function 0 returns a Buffer containing available functions. The args + * parameter is ignored for function 0, so just put 0 in it */ + if (dsm_func(test_handle, 0, 0, &result)) + return 0; + + /* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If + * the n-th bit is enabled, function n is supported */ + return result & 1 && result & (1 << sfnc); +} + static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) { mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0); @@ -168,6 +187,10 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) { + /* perhaps the _DSM functions are mutually exclusive, but prepare for + * the future */ + if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected) + return 0; if (id == VGA_SWITCHEROO_IGD) return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); else @@ -180,6 +203,11 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, if (id == VGA_SWITCHEROO_IGD) return 0; + /* Optimus laptops have the card already disabled in + * nouveau_switcheroo_set_state */ + if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected) + return 0; + return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); } @@ -212,8 +240,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) { acpi_handle dhandle, nvidia_handle; acpi_status status; - int ret, retval = 0; - uint32_t result; + int retval = 0; dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); if (!dhandle) @@ -224,13 +251,11 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) return false; } - ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, - NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); - if (ret == 0) + if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; - ret = nouveau_optimus_dsm(dhandle, 0, 0, &result); - if (ret == 0) + if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm, + NOUVEAU_DSM_OPTIMUS_FN)) retval |= NOUVEAU_DSM_HAS_OPT; if (retval) @@ -269,15 +294,22 @@ static bool nouveau_dsm_detect(void) } if (vga_count == 2 && has_dsm && guid_valid) { - acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, + &buffer); printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", - acpi_method_name); + acpi_method_name); nouveau_dsm_priv.dsm_detected = true; ret = true; } - if (has_optimus == 1) + if (has_optimus == 1) { + acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, + &buffer); + printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", + acpi_method_name); nouveau_dsm_priv.optimus_detected = true; + ret = true; + } return ret; } @@ -293,6 +325,17 @@ void nouveau_register_dsm_handler(void) vga_switcheroo_register_handler(&nouveau_dsm_handler); } +/* Must be called for Optimus models before the card can be turned off */ +void nouveau_switcheroo_optimus_dsm(void) +{ + u32 result = 0; + if (!nouveau_dsm_priv.optimus_detected) + return; + + nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FN, + NOUVEAU_DSM_OPTIMUS_ARGS, &result); +} + void nouveau_unregister_dsm_handler(void) { vga_switcheroo_unregister_handler(); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 38134a9c7578..b82709828931 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1055,12 +1055,14 @@ extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); #if defined(CONFIG_ACPI) void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); +void nouveau_switcheroo_optimus_dsm(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); int nouveau_acpi_edid(struct drm_device *, struct drm_connector *); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} +static inline void nouveau_switcheroo_optimus_dsm(void) {} static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index f5e98910d17f..f80c5e0762ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -525,6 +525,7 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev, printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(dev); + nouveau_switcheroo_optimus_dsm(); nouveau_pci_suspend(pdev, pmm); dev->switch_power_state = DRM_SWITCH_POWER_OFF; } diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index f7442e62c03f..8e8cd85e5c00 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -1793,10 +1793,12 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) ret = -EINVAL; break; case PACKET_TYPE2: + idx += 1; break; case PACKET_TYPE3: pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]); ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt); + idx += pkt.count + 2; break; default: dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type); @@ -1805,7 +1807,6 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) } if (ret) break; - idx += pkt.count + 2; } while (idx < ib->length_dw); return ret; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3ec81c3d5108..bfd36ab643a6 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2186,7 +2186,6 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) void r100_bm_disable(struct radeon_device *rdev) { u32 tmp; - u16 tmp16; /* disable bus mastering */ tmp = RREG32(R_000030_BUS_CNTL); @@ -2197,8 +2196,7 @@ void r100_bm_disable(struct radeon_device *rdev) WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); tmp = RREG32(RADEON_BUS_CNTL); mdelay(1); - pci_read_config_word(rdev->pdev, 0x4, &tmp16); - pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB); + pci_clear_master(rdev->pdev); mdelay(1); } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 31da622eef63..8032f1fedb11 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -145,7 +145,7 @@ module_param_named(vramlimit, radeon_vram_limit, int, 0600); MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); module_param_named(agpmode, radeon_agpmode, int, 0444); -MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n"); +MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc)"); module_param_named(gartsize, radeon_gart_size, int, 0600); MODULE_PARM_DESC(benchmark, "Run benchmark"); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 803e0d3c1773..ec46eb45e34c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -322,16 +322,6 @@ void rs600_hpd_fini(struct radeon_device *rdev) } } -void rs600_bm_disable(struct radeon_device *rdev) -{ - u16 tmp; - - /* disable bus mastering */ - pci_read_config_word(rdev->pdev, 0x4, &tmp); - pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); - mdelay(1); -} - int rs600_asic_reset(struct radeon_device *rdev) { struct rv515_mc_save save; @@ -355,7 +345,8 @@ int rs600_asic_reset(struct radeon_device *rdev) WREG32(RADEON_CP_RB_CNTL, tmp); pci_save_state(rdev->pdev); /* disable bus mastering */ - rs600_bm_disable(rdev); + pci_clear_master(rdev->pdev); + mdelay(1); /* reset GA+VAP */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | S_0000F0_SOFT_RESET_GA(1)); diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 37ead6995c87..0c46d8cdc6ea 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -952,10 +952,9 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) type = ttm_to_type(ttm->page_flags, ttm->caching_state); pool = ttm_dma_find_pool(dev, type); - if (!pool) { - WARN_ON(!pool); + if (!pool) return; - } + is_cached = (ttm_dma_find_pool(pool->dev, ttm_to_type(ttm->page_flags, tt_cached)) == pool); diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index f779009104eb..b71b77ab0dc7 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -90,7 +90,7 @@ static const char longname[] = "Prodikeys PC-MIDI Keyboard"; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; module_param_array(index, int, NULL, 0444); module_param_array(id, charp, NULL, 0444); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index cb351d358387..02260406b9e4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -474,8 +474,8 @@ config SENSORS_IT87 select HWMON_VID help If you say yes here you get support for ITE IT8705F, IT8712F, - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor - chips, and the SiS960 clone. + IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F and IT8758E + sensor chips, and the SiS960 clone. This driver can also be built as a module. If so, the module will be called it87. @@ -515,11 +515,11 @@ config SENSORS_LINEAGE will be called lineage-pem. config SENSORS_LM63 - tristate "National Semiconductor LM63 and LM64" + tristate "National Semiconductor LM63 and compatibles" depends on I2C help If you say yes here you get support for the National - Semiconductor LM63 and LM64 remote diode digital temperature + Semiconductor LM63, LM64, and LM96163 remote diode digital temperature sensors with integrated fan control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro) motherboard, among others. diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 65a35cf5b3c5..3b728e8f169b 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -145,7 +145,7 @@ static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 }; /* Insmod parameters */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Set to one to force detection."); static int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1, diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index d30855a75786..34a14a77e008 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -603,11 +603,11 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { /* Insmod parameters */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Set to one to force detection."); /* Default verbose is 1, since this driver is still in the testing phase */ -static int verbose = 1; +static bool verbose = 1; module_param(verbose, bool, 0644); MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting"); diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 522860ab6ce8..554f046bcf20 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -58,7 +58,7 @@ ACPI_MODULE_NAME(ACPI_POWER_METER_NAME); #define POWER_ALARM_NAME "power1_alarm" static int cap_in_hardware; -static int force_cap_on; +static bool force_cap_on; static int can_cap_in_hardware(void) { diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 1ad0a885c5a5..0158cc35cb2e 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -103,7 +103,7 @@ static int adm1021_remove(struct i2c_client *client); static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ -static int read_only; +static bool read_only; static const struct i2c_device_id adm1021_id[] = { diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index e6291dafa4ca..97e2cfb0bc93 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -155,7 +155,8 @@ adm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value) #define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \ (val) | 0x70 : (val)) -#define FAN_FROM_REG(reg, div) ((reg) ? (11250 * 60) / ((reg) * (div)) : 0) +#define FAN_FROM_REG(reg, div) ((reg) ? \ + (11250 * 60) / ((reg) * (div)) : 0) static int FAN_TO_REG(int reg, int div) { @@ -174,8 +175,8 @@ static int FAN_TO_REG(int reg, int div) (((reg) & 0x1F) | (((val) << 5) & 0xe0)) #define AUTO_TEMP_MIN_TO_REG(val, reg) \ - ((((val)/500) & 0xf8)|((reg) & 0x7)) -#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1<< ((reg)&0x7))) + ((((val) / 500) & 0xf8) | ((reg) & 0x7)) +#define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7))) #define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2)) #define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2) @@ -202,7 +203,7 @@ static int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm) /* FAN auto control */ #define GET_FAN_AUTO_BITFIELD(data, idx) \ - (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx%2] + (*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2] /* The tables below contains the possible values for the auto fan * control bitfields. the index in the table is the register value. @@ -230,7 +231,7 @@ static const auto_chan_table_t auto_channel_select_table_adm1030 = { */ static int get_fan_auto_nearest(struct adm1031_data *data, - int chan, u8 val, u8 reg, u8 * new_reg) + int chan, u8 val, u8 reg, u8 *new_reg) { int i; int first_match = -1, exact_match = -1; @@ -258,13 +259,13 @@ get_fan_auto_nearest(struct adm1031_data *data, } } - if (exact_match >= 0) { + if (exact_match >= 0) *new_reg = exact_match; - } else if (first_match >= 0) { + else if (first_match >= 0) *new_reg = first_match; - } else { + else return -EINVAL; - } + return 0; } @@ -283,23 +284,28 @@ set_fan_auto_channel(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; u8 reg; int ret; u8 old_fan_mode; + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + old_fan_mode = data->conf1; mutex_lock(&data->update_lock); - if ((ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®))) { + ret = get_fan_auto_nearest(data, nr, val, data->conf1, ®); + if (ret) { mutex_unlock(&data->update_lock); return ret; } data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1); if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^ (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) { - if (data->conf1 & ADM1031_CONF1_AUTO_MODE){ + if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { /* Switch to Auto Fan Mode * Save PWM registers * Set PWM registers to 33% Both */ @@ -350,7 +356,12 @@ set_auto_temp_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]); @@ -374,10 +385,16 @@ set_auto_temp_max(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); - data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], data->pwm[nr]); + data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr], + data->pwm[nr]); adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr), data->temp_max[nr]); mutex_unlock(&data->update_lock); @@ -410,8 +427,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); - int reg; + long val; + int ret, reg; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) && @@ -449,9 +470,13 @@ static int trust_fan_readings(struct adm1031_data *data, int chan) if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { switch (data->conf1 & 0x60) { - case 0x00: /* remote temp1 controls fan1 remote temp2 controls fan2 */ + case 0x00: + /* + * remote temp1 controls fan1, + * remote temp2 controls fan2 + */ res = data->temp[chan+1] >= - AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); + AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]); break; case 0x20: /* remote temp1 controls both fans */ res = @@ -515,7 +540,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; mutex_lock(&data->update_lock); if (val) { @@ -534,10 +564,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val = simple_strtol(buf, NULL, 10); + long val; u8 tmp; int old_div; int new_min; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; tmp = val == 8 ? 0xc0 : val == 4 ? 0x80 : @@ -631,9 +666,13 @@ static ssize_t set_temp_offset(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -15000, 15000); mutex_lock(&data->update_lock); data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val); @@ -648,9 +687,13 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_min[nr] = TEMP_TO_REG(val); @@ -665,9 +708,13 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_max[nr] = TEMP_TO_REG(val); @@ -682,9 +729,13 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *attr, struct i2c_client *client = to_i2c_client(dev); struct adm1031_data *data = i2c_get_clientdata(client); int nr = to_sensor_dev_attr(attr)->index; - int val; + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; - val = simple_strtol(buf, NULL, 10); val = SENSORS_LIMIT(val, -55000, nr == 0 ? 127750 : 127875); mutex_lock(&data->update_lock); data->temp_crit[nr] = TEMP_TO_REG(val); @@ -711,7 +762,8 @@ temp_reg(2); temp_reg(3); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", data->alarm); @@ -919,12 +971,13 @@ static int adm1031_probe(struct i2c_client *client, adm1031_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group))) + err = sysfs_create_group(&client->dev.kobj, &adm1031_group); + if (err) goto exit_free; if (data->chip_type == adm1031) { - if ((err = sysfs_create_group(&client->dev.kobj, - &adm1031_group_opt))) + err = sysfs_create_group(&client->dev.kobj, &adm1031_group_opt); + if (err) goto exit_remove; } @@ -970,14 +1023,13 @@ static void adm1031_init_client(struct i2c_client *client) } /* Initialize the ADM1031 chip (enables fan speed reading ) */ read_val = adm1031_read_value(client, ADM1031_REG_CONF2); - if ((read_val | mask) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); - } + if ((read_val | mask) != read_val) + adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask); read_val = adm1031_read_value(client, ADM1031_REG_CONF1); if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { - adm1031_write_value(client, ADM1031_REG_CONF1, read_val | - ADM1031_CONF1_MONITOR_ENABLE); + adm1031_write_value(client, ADM1031_REG_CONF1, + read_val | ADM1031_CONF1_MONITOR_ENABLE); } /* Read the chip's update rate */ @@ -1024,8 +1076,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) /* oldh is actually newer */ if (newh != oldh) dev_warn(&client->dev, - "Remote temperature may be " - "wrong.\n"); + "Remote temperature may be wrong.\n"); #endif } data->temp[chan] = newh; @@ -1052,22 +1103,24 @@ static struct adm1031_data *adm1031_update_device(struct device *dev) data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0)) - | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) - << 8); - if (data->chip_type == adm1030) { + | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8); + if (data->chip_type == adm1030) data->alarm &= 0xc0ff; - } - for (chan=0; chan<(data->chip_type == adm1030 ? 1 : 2); chan++) { + for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2); + chan++) { data->fan_div[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_DIV(chan)); + adm1031_read_value(client, + ADM1031_REG_FAN_DIV(chan)); data->fan_min[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_MIN(chan)); + adm1031_read_value(client, + ADM1031_REG_FAN_MIN(chan)); data->fan[chan] = - adm1031_read_value(client, ADM1031_REG_FAN_SPEED(chan)); + adm1031_read_value(client, + ADM1031_REG_FAN_SPEED(chan)); data->pwm[chan] = - 0xf & (adm1031_read_value(client, ADM1031_REG_PWM) >> - (4*chan)); + (adm1031_read_value(client, + ADM1031_REG_PWM) >> (4 * chan)) & 0x0f; } data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index cfcc3b6fb6bf..ed60242d6a0a 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -48,8 +48,8 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; /* Module parameters */ -static int se_input = 1; /* Default is SE, 0 == diff */ -static int int_vref = 1; /* Default is internal ref ON */ +static bool se_input = 1; /* Default is SE, 0 == diff */ +static bool int_vref = 1; /* Default is internal ref ON */ static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */ module_param(se_input, bool, S_IRUGO); module_param(int_vref, bool, S_IRUGO); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 1fdef885341c..a6c6ec36615e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -190,7 +190,8 @@ static ssize_t show_temp(struct device *dev, return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN; } -static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) +static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, + struct device *dev) { /* The 100C is default for both mobile and non mobile CPUs */ @@ -284,7 +285,8 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return tjmax; } -static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) +static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id, + struct device *dev) { int err; u32 eax, edx; @@ -323,7 +325,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return adjust_tjmax(c, id, dev); } -static int create_name_attr(struct platform_data *pdata, struct device *dev) +static int __devinit create_name_attr(struct platform_data *pdata, + struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); pdata->name_attr.attr.name = "name"; @@ -332,8 +335,8 @@ static int create_name_attr(struct platform_data *pdata, struct device *dev) return device_create_file(dev, &pdata->name_attr); } -static int create_core_attrs(struct temp_data *tdata, struct device *dev, - int attr_no) +static int __cpuinit create_core_attrs(struct temp_data *tdata, + struct device *dev, int attr_no) { int err, i; static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev, @@ -383,7 +386,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu) return 0; } -static struct platform_device *coretemp_get_pdev(unsigned int cpu) +static struct platform_device __cpuinit *coretemp_get_pdev(unsigned int cpu) { u16 phys_proc_id = TO_PHYS_ID(cpu); struct pdev_entry *p; @@ -400,7 +403,8 @@ static struct platform_device *coretemp_get_pdev(unsigned int cpu) return NULL; } -static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) +static struct temp_data __cpuinit *init_temp_data(unsigned int cpu, + int pkg_flag) { struct temp_data *tdata; @@ -418,7 +422,7 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) return tdata; } -static int create_core_data(struct platform_device *pdev, +static int __cpuinit create_core_data(struct platform_device *pdev, unsigned int cpu, int pkg_flag) { struct temp_data *tdata; @@ -489,7 +493,7 @@ exit_free: return err; } -static void coretemp_add_core(unsigned int cpu, int pkg_flag) +static void __cpuinit coretemp_add_core(unsigned int cpu, int pkg_flag) { struct platform_device *pdev = coretemp_get_pdev(cpu); int err; @@ -618,7 +622,7 @@ exit: return err; } -static void coretemp_device_remove(unsigned int cpu) +static void __cpuinit coretemp_device_remove(unsigned int cpu) { struct pdev_entry *p, *n; u16 phys_proc_id = TO_PHYS_ID(cpu); @@ -634,7 +638,7 @@ static void coretemp_device_remove(unsigned int cpu) mutex_unlock(&pdev_list_mutex); } -static bool is_any_core_online(struct platform_data *pdata) +static bool __cpuinit is_any_core_online(struct platform_data *pdata) { int i; diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index d9803958e49f..ffb229af7861 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -45,7 +45,7 @@ static struct platform_device *pdev; /* Module load parameters */ -static int force_start; +static bool force_start; module_param(force_start, bool, 0); MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs"); @@ -53,7 +53,7 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -static int probe_all_addr; +static bool probe_all_addr; module_param(probe_all_addr, bool, 0); MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC " "addresses"); diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 848a2b0bc83f..865063914d76 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -55,7 +55,7 @@ static const u8 REG_TEMP_MAX[4] = { 0x34, 0x30, 0x31, 0x32 }; * it. Default is to leave the device in the state it's already in (-1). * This parameter allows APD mode to be optionally forced on or off */ static int apd = -1; -module_param(apd, bool, 0); +module_param(apd, bint, 0); MODULE_PARM_DESC(init, "Set to zero to disable anti-parallel diode mode"); struct temperature { diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 38c0b87676de..0054d6f9cec9 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -17,6 +17,7 @@ * IT8720F Super I/O chip w/LPC interface * IT8721F Super I/O chip w/LPC interface * IT8726F Super I/O chip w/LPC interface + * IT8728F Super I/O chip w/LPC interface * IT8758E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * @@ -58,7 +59,7 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720, it8721 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -135,6 +136,7 @@ static inline void superio_exit(void) #define IT8720F_DEVID 0x8720 #define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 +#define IT8728F_DEVID 0x8728 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -146,10 +148,10 @@ static inline void superio_exit(void) #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ /* Update battery voltage after every reading if true */ -static int update_vbat; +static bool update_vbat; /* Not all BIOSes properly configure the PWM registers */ -static int fix_pwm_polarity; +static bool fix_pwm_polarity; /* Many IT87 constants specified below */ @@ -274,11 +276,31 @@ struct it87_data { s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ }; +static inline int has_12mv_adc(const struct it87_data *data) +{ + /* + * IT8721F and later have a 12 mV ADC, also with internal scaling + * on selected inputs. + */ + return data->type == it8721 + || data->type == it8728; +} + +static inline int has_newer_autopwm(const struct it87_data *data) +{ + /* + * IT8721F and later have separate registers for the temperature + * mapping and the manual duty cycle. + */ + return data->type == it8721 + || data->type == it8728; +} + static u8 in_to_reg(const struct it87_data *data, int nr, long val) { long lsb; - if (data->type == it8721) { + if (has_12mv_adc(data)) { if (data->in_scaled & (1 << nr)) lsb = 24; else @@ -292,7 +314,7 @@ static u8 in_to_reg(const struct it87_data *data, int nr, long val) static int in_from_reg(const struct it87_data *data, int nr, int val) { - if (data->type == it8721) { + if (has_12mv_adc(data)) { if (data->in_scaled & (1 << nr)) return val * 24; else @@ -329,7 +351,7 @@ static inline u16 FAN16_TO_REG(long rpm) static u8 pwm_to_reg(const struct it87_data *data, long val) { - if (data->type == it8721) + if (has_newer_autopwm(data)) return val; else return val >> 1; @@ -337,7 +359,7 @@ static u8 pwm_to_reg(const struct it87_data *data, long val) static int pwm_from_reg(const struct it87_data *data, u8 reg) { - if (data->type == it8721) + if (has_newer_autopwm(data)) return reg; else return (reg & 0x7f) << 1; @@ -374,7 +396,8 @@ static inline int has_16bit_fans(const struct it87_data *data) || data->type == it8716 || data->type == it8718 || data->type == it8720 - || data->type == it8721; + || data->type == it8721 + || data->type == it8728; } static inline int has_old_autopwm(const struct it87_data *data) @@ -842,7 +865,7 @@ static ssize_t set_pwm_enable(struct device *dev, data->fan_main_ctrl); } else { if (val == 1) /* Manual mode */ - data->pwm_ctrl[nr] = data->type == it8721 ? + data->pwm_ctrl[nr] = has_newer_autopwm(data) ? data->pwm_temp_map[nr] : data->pwm_duty[nr]; else /* Automatic mode */ @@ -870,7 +893,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - if (data->type == it8721) { + if (has_newer_autopwm(data)) { /* If we are in automatic mode, the PWM duty cycle register * is read-only so we can't write the value */ if (data->pwm_ctrl[nr] & 0x80) { @@ -1311,8 +1334,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; - return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr] - : labels[nr]); + return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] + : labels[nr]); } static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); @@ -1605,6 +1628,9 @@ static int __init it87_find(unsigned short *address, case IT8721F_DEVID: sio_data->type = it8721; break; + case IT8728F_DEVID: + sio_data->type = it8728; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -1646,8 +1672,11 @@ static int __init it87_find(unsigned short *address, superio_select(GPIO); reg = superio_inb(IT87_SIO_GPIO3_REG); - if (sio_data->type == it8721) { - /* The IT8721F/IT8758E doesn't have VID pins at all */ + if (sio_data->type == it8721 || sio_data->type == it8728) { + /* + * The IT8721F/IT8758E doesn't have VID pins at all, + * not sure about the IT8728F. + */ sio_data->skip_vid = 1; } else { /* We need at least 4 VID pins */ @@ -1692,7 +1721,8 @@ static int __init it87_find(unsigned short *address, } if (reg & (1 << 0)) sio_data->internal |= (1 << 0); - if ((reg & (1 << 1)) || sio_data->type == it8721) + if ((reg & (1 << 1)) || sio_data->type == it8721 || + sio_data->type == it8728) sio_data->internal |= (1 << 1); sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; @@ -1770,6 +1800,7 @@ static int __devinit it87_probe(struct platform_device *pdev) "it8718", "it8720", "it8721", + "it8728", }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); @@ -1807,7 +1838,7 @@ static int __devinit it87_probe(struct platform_device *pdev) enable_pwm_interface = it87_check_pwm(dev); /* Starting with IT8721F, we handle scaling of internal voltages */ - if (data->type == it8721) { + if (has_12mv_adc(data)) { if (sio_data->internal & (1 << 0)) data->in_scaled |= (1 << 3); /* in3 is AVCC */ if (sio_data->internal & (1 << 1)) @@ -2093,7 +2124,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) static void it87_update_pwm_ctrl(struct it87_data *data, int nr) { data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr)); - if (data->type == it8721) { + if (has_newer_autopwm(data)) { data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; data->pwm_duty[nr] = it87_read_value(data, IT87_REG_PWM_DUTY(nr)); diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 508cb291f71b..5e6457a6644d 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -47,10 +47,14 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> +#include <linux/types.h> /* * Addresses to scan - * Address is fully defined internally and cannot be changed. + * Address is fully defined internally and cannot be changed except for + * LM64 which has one pin dedicated to address selection. + * LM63 and LM96163 have address 0x4c. + * LM64 can have address 0x18 or 0x4e. */ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; @@ -60,6 +64,7 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; */ #define LM63_REG_CONFIG1 0x03 +#define LM63_REG_CONVRATE 0x04 #define LM63_REG_CONFIG2 0xBF #define LM63_REG_CONFIG_FAN 0x4A @@ -70,6 +75,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; #define LM63_REG_PWM_VALUE 0x4C #define LM63_REG_PWM_FREQ 0x4D +#define LM63_REG_LUT_TEMP_HYST 0x4F +#define LM63_REG_LUT_TEMP(nr) (0x50 + 2 * (nr)) +#define LM63_REG_LUT_PWM(nr) (0x51 + 2 * (nr)) #define LM63_REG_LOCAL_TEMP 0x00 #define LM63_REG_LOCAL_HIGH 0x05 @@ -91,6 +99,16 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; #define LM63_REG_MAN_ID 0xFE #define LM63_REG_CHIP_ID 0xFF +#define LM96163_REG_TRUTHERM 0x30 +#define LM96163_REG_REMOTE_TEMP_U_MSB 0x31 +#define LM96163_REG_REMOTE_TEMP_U_LSB 0x32 +#define LM96163_REG_CONFIG_ENHANCED 0x45 + +#define LM63_MAX_CONVRATE 9 + +#define LM63_MAX_CONVRATE_HZ 32 +#define LM96163_MAX_CONVRATE_HZ 26 + /* * Conversions and various macros * For tachometer counts, the LM63 uses 16-bit values. @@ -112,15 +130,24 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END }; (val) >= 127000 ? 127 : \ (val) < 0 ? ((val) - 500) / 1000 : \ ((val) + 500) / 1000) +#define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 255000 ? 255 : \ + ((val) + 500) / 1000) #define TEMP11_FROM_REG(reg) ((reg) / 32 * 125) #define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \ (val) >= 127875 ? 0x7FE0 : \ (val) < 0 ? ((val) - 62) / 125 * 32 : \ ((val) + 62) / 125 * 32) +#define TEMP11U_TO_REG(val) ((val) <= 0 ? 0 : \ + (val) >= 255875 ? 0xFFE0 : \ + ((val) + 62) / 125 * 32) #define HYST_TO_REG(val) ((val) <= 0 ? 0 : \ (val) >= 127000 ? 127 : \ ((val) + 500) / 1000) +#define UPDATE_INTERVAL(max, rate) \ + ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max)) + /* * Functions declaration */ @@ -134,7 +161,7 @@ static struct lm63_data *lm63_update_device(struct device *dev); static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info); static void lm63_init_client(struct i2c_client *client); -enum chips { lm63, lm64 }; +enum chips { lm63, lm64, lm96163 }; /* * Driver data (common to all clients) @@ -143,6 +170,7 @@ enum chips { lm63, lm64 }; static const struct i2c_device_id lm63_id[] = { { "lm63", lm63 }, { "lm64", lm64 }, + { "lm96163", lm96163 }, { } }; MODULE_DEVICE_TABLE(i2c, lm63_id); @@ -167,26 +195,53 @@ struct lm63_data { struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ + char lut_valid; /* zero until lut fields are valid */ unsigned long last_updated; /* in jiffies */ - int kind; + unsigned long lut_last_updated; /* in jiffies */ + enum chips kind; int temp2_offset; + int update_interval; /* in milliseconds */ + int max_convrate_hz; + int lut_size; /* 8 or 12 */ + /* registers values */ u8 config, config_fan; u16 fan[2]; /* 0: input 1: low limit */ u8 pwm1_freq; - u8 pwm1_value; - s8 temp8[3]; /* 0: local input + u8 pwm1[13]; /* 0: current output + 1-12: lookup table */ + s8 temp8[15]; /* 0: local input 1: local high limit - 2: remote critical limit */ - s16 temp11[3]; /* 0: remote input + 2: remote critical limit + 3-14: lookup table */ + s16 temp11[4]; /* 0: remote input 1: remote low limit - 2: remote high limit */ + 2: remote high limit + 3: remote offset */ + u16 temp11u; /* remote input (unsigned) */ u8 temp2_crit_hyst; + u8 lut_temp_hyst; u8 alarms; + bool pwm_highres; + bool lut_temp_highres; + bool remote_unsigned; /* true if unsigned remote upper limits */ + bool trutherm; }; +static inline int temp8_from_reg(struct lm63_data *data, int nr) +{ + if (data->remote_unsigned) + return TEMP8_FROM_REG((u8)data->temp8[nr]); + return TEMP8_FROM_REG(data->temp8[nr]); +} + +static inline int lut_temp_from_reg(struct lm63_data *data, int nr) +{ + return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000); +} + /* * Sysfs callback functions and files */ @@ -204,7 +259,12 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); data->fan[1] = FAN_TO_REG(val); @@ -216,13 +276,22 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, return count; } -static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy, +static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr, char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ? - 255 : (data->pwm1_value * 255 + data->pwm1_freq) / - (2 * data->pwm1_freq)); + int nr = attr->index; + int pwm; + + if (data->pwm_highres) + pwm = data->pwm1[nr]; + else + pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ? + 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) / + (2 * data->pwm1_freq); + + return sprintf(buf, "%d\n", pwm); } static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, @@ -231,22 +300,26 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy, struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); unsigned long val; - + int err; + if (!(data->config_fan & 0x20)) /* register is read-only */ return -EPERM; - val = simple_strtoul(buf, NULL, 10); + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + val = SENSORS_LIMIT(val, 0, 255); mutex_lock(&data->update_lock); - data->pwm1_value = val <= 0 ? 0 : - val >= 255 ? 2 * data->pwm1_freq : - (val * data->pwm1_freq * 2 + 127) / 255; - i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value); + data->pwm1[0] = data->pwm_highres ? val : + (val * data->pwm1_freq * 2 + 127) / 255; + i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]); mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy, - char *buf) +static ssize_t show_pwm1_enable(struct device *dev, + struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); @@ -273,21 +346,47 @@ static ssize_t show_remote_temp8(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index]) + return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index) + + data->temp2_offset); +} + +static ssize_t show_lut_temp(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) + data->temp2_offset); } -static ssize_t set_local_temp8(struct device *dev, - struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + int nr = attr->index; + int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH; + long val; + int err; + int temp; + + err = kstrtol(buf, 10, &val); + if (err) + return err; mutex_lock(&data->update_lock); - data->temp8[1] = TEMP8_TO_REG(val); - i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]); + if (nr == 2) { + if (data->remote_unsigned) + temp = TEMP8U_TO_REG(val - data->temp2_offset); + else + temp = TEMP8_TO_REG(val - data->temp2_offset); + } else { + temp = TEMP8_TO_REG(val); + } + data->temp8[nr] = temp; + i2c_smbus_write_byte_data(client, reg, temp); mutex_unlock(&data->update_lock); return count; } @@ -297,28 +396,56 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index]) - + data->temp2_offset); + int nr = attr->index; + int temp; + + if (!nr) { + /* + * Use unsigned temperature unless its value is zero. + * If it is zero, use signed temperature. + */ + if (data->temp11u) + temp = TEMP11_FROM_REG(data->temp11u); + else + temp = TEMP11_FROM_REG(data->temp11[nr]); + } else { + if (data->remote_unsigned && nr == 2) + temp = TEMP11_FROM_REG((u16)data->temp11[nr]); + else + temp = TEMP11_FROM_REG(data->temp11[nr]); + } + return sprintf(buf, "%d\n", temp + data->temp2_offset); } static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - static const u8 reg[4] = { + static const u8 reg[6] = { LM63_REG_REMOTE_LOW_MSB, LM63_REG_REMOTE_LOW_LSB, LM63_REG_REMOTE_HIGH_MSB, LM63_REG_REMOTE_HIGH_LSB, + LM63_REG_REMOTE_OFFSET_MSB, + LM63_REG_REMOTE_OFFSET_LSB, }; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; int nr = attr->index; + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); - data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); + if (data->remote_unsigned && nr == 2) + data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset); + else + data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset); + i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], data->temp11[nr] >> 8); i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], @@ -327,35 +454,143 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, return count; } -/* Hysteresis register holds a relative value, while we want to present - an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, - char *buf) +/* + * Hysteresis register holds a relative value, while we want to present + * an absolute to user-space + */ +static ssize_t show_temp2_crit_hyst(struct device *dev, + struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); - return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2]) + return sprintf(buf, "%d\n", temp8_from_reg(data, 2) + data->temp2_offset - TEMP8_FROM_REG(data->temp2_crit_hyst)); } -/* And now the other way around, user-space provides an absolute - hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy, +static ssize_t show_lut_temp_hyst(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm63_data *data = lm63_update_device(dev); + + return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) + + data->temp2_offset + - TEMP8_FROM_REG(data->lut_temp_hyst)); +} + +/* + * And now the other way around, user-space provides an absolute + * hysteresis value and we have to store a relative one + */ +static ssize_t set_temp2_crit_hyst(struct device *dev, + struct device_attribute *dummy, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + long val; + int err; long hyst; + err = kstrtol(buf, 10, &val); + if (err) + return err; + mutex_lock(&data->update_lock); - hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val; + hyst = temp8_from_reg(data, 2) + data->temp2_offset - val; i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST, HYST_TO_REG(hyst)); mutex_unlock(&data->update_lock); return count; } +/* + * Set conversion rate. + * client->update_lock must be held when calling this function. + */ +static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data, + unsigned int interval) +{ + int i; + unsigned int update_interval; + + /* Shift calculations to avoid rounding errors */ + interval <<= 6; + + /* find the nearest update rate */ + update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000 + / data->max_convrate_hz; + for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1) + if (interval >= update_interval * 3 / 4) + break; + + i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i); + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i); +} + +static ssize_t show_update_interval(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm63_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->update_interval); +} + +static ssize_t set_update_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val; + int err; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + mutex_lock(&data->update_lock); + lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_type(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + + return sprintf(buf, data->trutherm ? "1\n" : "2\n"); +} + +static ssize_t set_type(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + unsigned long val; + int ret; + u8 reg; + + ret = kstrtoul(buf, 10, &val); + if (ret < 0) + return ret; + if (val != 1 && val != 2) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->trutherm = val == 1; + reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02; + i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM, + reg | (data->trutherm ? 0x02 : 0x00)); + data->valid = 0; + mutex_unlock(&data->update_lock); + + return count; +} + static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, char *buf) { @@ -377,27 +612,87 @@ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, set_fan, 1); -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1); +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0); static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL); +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO, + show_lut_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, + show_lut_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 4); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO, + show_lut_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 5); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO, + show_lut_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO, + show_lut_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 7); +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO, + show_lut_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 8); +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7); +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO, + show_lut_temp, NULL, 9); +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 9); +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8); +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO, + show_lut_temp, NULL, 10); +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 10); +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9); +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO, + show_lut_temp, NULL, 11); +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 11); +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10); +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO, + show_lut_temp, NULL, 12); +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 12); +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11); +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO, + show_lut_temp, NULL, 13); +static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 13); +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12); +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO, + show_lut_temp, NULL, 14); +static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO, + show_lut_temp_hyst, NULL, 14); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8, - set_local_temp8, 1); + set_temp8, 1); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 1); static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 2); -/* - * On LM63, temp2_crit can be set only once, which should be job - * of the bootloader. - */ +static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 3); static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, - NULL, 2); + set_temp8, 2); static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, set_temp2_crit_hyst); +static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type); + /* Individual alarm files */ static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); @@ -408,14 +703,43 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); /* Raw alarm file for compatibility */ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, + set_update_interval); + static struct attribute *lm63_attributes[] = { - &dev_attr_pwm1.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, &dev_attr_pwm1_enable.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &dev_attr_temp2_crit_hyst.attr, @@ -425,10 +749,54 @@ static struct attribute *lm63_attributes[] = { &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, &dev_attr_alarms.attr, + &dev_attr_update_interval.attr, NULL }; +static struct attribute *lm63_attributes_extra_lut[] = { + &sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm63_group_extra_lut = { + .attrs = lm63_attributes_extra_lut, +}; + +/* + * On LM63, temp2_crit can be set only once, which should be job + * of the bootloader. + * On LM64, temp2_crit can always be set. + * On LM96163, temp2_crit can be set if bit 1 of the configuration + * register is true. + */ +static umode_t lm63_attribute_mode(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct i2c_client *client = to_i2c_client(dev); + struct lm63_data *data = i2c_get_clientdata(client); + + if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr + && (data->kind == lm64 || + (data->kind == lm96163 && (data->config & 0x02)))) + return attr->mode | S_IWUSR; + + return attr->mode; +} + static const struct attribute_group lm63_group = { + .is_visible = lm63_attribute_mode, .attrs = lm63_attributes, }; @@ -487,6 +855,8 @@ static int lm63_detect(struct i2c_client *new_client, strlcpy(info->type, "lm63", I2C_NAME_SIZE); else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e)) strlcpy(info->type, "lm64", I2C_NAME_SIZE); + else if (chip_id == 0x49 && address == 0x4c) + strlcpy(info->type, "lm96163", I2C_NAME_SIZE); else return -ENODEV; @@ -518,12 +888,24 @@ static int lm63_probe(struct i2c_client *new_client, lm63_init_client(new_client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, - &lm63_group))) + err = sysfs_create_group(&new_client->dev.kobj, &lm63_group); + if (err) goto exit_free; if (data->config & 0x04) { /* tachometer enabled */ - if ((err = sysfs_create_group(&new_client->dev.kobj, - &lm63_group_fan1))) + err = sysfs_create_group(&new_client->dev.kobj, + &lm63_group_fan1); + if (err) + goto exit_remove_files; + } + if (data->kind == lm96163) { + err = device_create_file(&new_client->dev, + &dev_attr_temp2_type); + if (err) + goto exit_remove_files; + + err = sysfs_create_group(&new_client->dev.kobj, + &lm63_group_extra_lut); + if (err) goto exit_remove_files; } @@ -538,17 +920,25 @@ static int lm63_probe(struct i2c_client *new_client, exit_remove_files: sysfs_remove_group(&new_client->dev.kobj, &lm63_group); sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1); + if (data->kind == lm96163) { + device_remove_file(&new_client->dev, &dev_attr_temp2_type); + sysfs_remove_group(&new_client->dev.kobj, + &lm63_group_extra_lut); + } exit_free: kfree(data); exit: return err; } -/* Idealy we shouldn't have to initialize anything, since the BIOS - should have taken care of everything */ +/* + * Ideally we shouldn't have to initialize anything, since the BIOS + * should have taken care of everything + */ static void lm63_init_client(struct i2c_client *client) { struct lm63_data *data = i2c_get_clientdata(client); + u8 convrate; data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1); data->config_fan = i2c_smbus_read_byte_data(client, @@ -561,16 +951,57 @@ static void lm63_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1, data->config); } + /* Tachometer is always enabled on LM64 */ + if (data->kind == lm64) + data->config |= 0x04; /* We may need pwm1_freq before ever updating the client data */ data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ); if (data->pwm1_freq == 0) data->pwm1_freq = 1; + switch (data->kind) { + case lm63: + case lm64: + data->max_convrate_hz = LM63_MAX_CONVRATE_HZ; + data->lut_size = 8; + break; + case lm96163: + data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ; + data->lut_size = 12; + data->trutherm + = i2c_smbus_read_byte_data(client, + LM96163_REG_TRUTHERM) & 0x02; + break; + } + convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE); + if (unlikely(convrate > LM63_MAX_CONVRATE)) + convrate = LM63_MAX_CONVRATE; + data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, + convrate); + + /* + * For LM96163, check if high resolution PWM + * and unsigned temperature format is enabled. + */ + if (data->kind == lm96163) { + u8 config_enhanced + = i2c_smbus_read_byte_data(client, + LM96163_REG_CONFIG_ENHANCED); + if (config_enhanced & 0x20) + data->lut_temp_highres = true; + if ((config_enhanced & 0x10) + && !(data->config_fan & 0x08) && data->pwm1_freq == 8) + data->pwm_highres = true; + if (config_enhanced & 0x08) + data->remote_unsigned = true; + } + /* Show some debug info about the LM63 configuration */ - dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", - (data->config & 0x04) ? "tachometer input" : - "alert output"); + if (data->kind == lm63) + dev_dbg(&client->dev, "Alert/tach pin configured for %s\n", + (data->config & 0x04) ? "tachometer input" : + "alert output"); dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n", (data->config_fan & 0x08) ? "1.4" : "360", ((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq); @@ -586,6 +1017,10 @@ static int lm63_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm63_group); sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); + if (data->kind == lm96163) { + device_remove_file(&client->dev, &dev_attr_temp2_type); + sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut); + } kfree(data); return 0; @@ -595,10 +1030,15 @@ static struct lm63_data *lm63_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm63_data *data = i2c_get_clientdata(client); + unsigned long next_update; + int i; mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval) + 1; + + if (time_after(jiffies, next_update) || !data->valid) { if (data->config & 0x04) { /* tachometer enabled */ /* order matters for fan1_input */ data->fan[0] = i2c_smbus_read_byte_data(client, @@ -615,8 +1055,8 @@ static struct lm63_data *lm63_update_device(struct device *dev) LM63_REG_PWM_FREQ); if (data->pwm1_freq == 0) data->pwm1_freq = 1; - data->pwm1_value = i2c_smbus_read_byte_data(client, - LM63_REG_PWM_VALUE); + data->pwm1[0] = i2c_smbus_read_byte_data(client, + LM63_REG_PWM_VALUE); data->temp8[0] = i2c_smbus_read_byte_data(client, LM63_REG_LOCAL_TEMP); @@ -636,6 +1076,17 @@ static struct lm63_data *lm63_update_device(struct device *dev) LM63_REG_REMOTE_HIGH_MSB) << 8) | i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_HIGH_LSB); + data->temp11[3] = (i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_OFFSET_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM63_REG_REMOTE_OFFSET_LSB); + + if (data->kind == lm96163) + data->temp11u = (i2c_smbus_read_byte_data(client, + LM96163_REG_REMOTE_TEMP_U_MSB) << 8) + | i2c_smbus_read_byte_data(client, + LM96163_REG_REMOTE_TEMP_U_LSB); + data->temp8[2] = i2c_smbus_read_byte_data(client, LM63_REG_REMOTE_TCRIT); data->temp2_crit_hyst = i2c_smbus_read_byte_data(client, @@ -648,6 +1099,21 @@ static struct lm63_data *lm63_update_device(struct device *dev) data->valid = 1; } + if (time_after(jiffies, data->lut_last_updated + 5 * HZ) || + !data->lut_valid) { + for (i = 0; i < data->lut_size; i++) { + data->pwm1[1 + i] = i2c_smbus_read_byte_data(client, + LM63_REG_LUT_PWM(i)); + data->temp8[3 + i] = i2c_smbus_read_byte_data(client, + LM63_REG_LUT_TEMP(i)); + } + data->lut_temp_hyst = i2c_smbus_read_byte_data(client, + LM63_REG_LUT_TEMP_HYST); + + data->lut_last_updated = jiffies; + data->lut_valid = 1; + } + mutex_unlock(&data->update_lock); return data; diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index bdfd675488ae..d2dd5f90496d 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -917,7 +917,7 @@ static ssize_t set_update_interval(struct device *dev, return err; mutex_lock(&data->update_lock); - lm90_set_convrate(client, data, val); + lm90_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000)); mutex_unlock(&data->update_lock); return count; diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 3b43df418613..8bd6c5c9e05b 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -151,12 +151,12 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* Insmod parameters */ -static int disable_block; +static bool disable_block; module_param(disable_block, bool, 0); MODULE_PARM_DESC(disable_block, "Set to non-zero to disable SMBus block data transactions."); -static int init; +static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization."); diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 84ef3a898707..482ca901db30 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -106,11 +106,14 @@ static ssize_t show_adc(struct device *dev, if (ret < 0) return ret; - return sprintf(buf, "%d\n", ret); + /* assume the reference voltage to be 2.048V, with an 8-bit sample, + * the LSB weight is 8mV + */ + return sprintf(buf, "%d\n", ret * 8); } #define MAX1111_ADC_ATTR(_id) \ - SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id) + SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id) static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static MAX1111_ADC_ATTR(0); @@ -120,10 +123,10 @@ static MAX1111_ADC_ATTR(3); static struct attribute *max1111_attributes[] = { &dev_attr_name.attr, - &sensor_dev_attr_adc0_in.dev_attr.attr, - &sensor_dev_attr_adc1_in.dev_attr.attr, - &sensor_dev_attr_adc2_in.dev_attr.attr, - &sensor_dev_attr_adc3_in.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, NULL, }; diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 6914195cfd35..88953f99e914 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -59,7 +59,7 @@ static unsigned short max1668_addr_list[] = { #define DEV_ID_MAX1989 0xb /* read only mode module parameter */ -static int read_only; +static bool read_only; module_param(read_only, bool, 0); MODULE_PARM_DESC(read_only, "Don't set any values, read only mode"); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index bde50e34d013..374118f2b9f9 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -71,7 +71,7 @@ module_param(force_i2c, byte, 0); MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors"); -static int init = 1; +static bool init = 1; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 65b685e2c7b7..17a8fa2d9ae9 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -67,11 +67,11 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to one to reset chip on load"); -static int init = 1; +static bool init = 1; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 6e5d0ae594b0..35aa5149307a 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -58,11 +58,11 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset"); -static int init; +static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to one to force extra software initialization"); diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 9ded133e43f0..d3100eab6b2f 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -56,7 +56,7 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int init; +static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to one to force chip initialization"); diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 3cc6fef22087..45ec7e7c3c27 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -61,7 +61,7 @@ module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: " "{bus, clientaddr, subclientaddr1, subclientaddr2}"); -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 3ee398d0e4c9..aa58b25565bc 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -42,7 +42,7 @@ static const unsigned short normal_i2c[] = { }; -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 0254e181893d..063bd9508d8a 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -39,7 +39,7 @@ static const unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END }; /* Insmod parameters */ -static int reset; +static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a3afac4be734..cbe7a2fb779f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -299,11 +299,11 @@ config I2C_AT91 unless your system can cope with those limitations. config I2C_AU1550 - tristate "Au1550/Au1200 SMBus interface" + tristate "Au1550/Au1200/Au1300 SMBus interface" depends on MIPS_ALCHEMY help If you say yes to this option, support will be included for the - Au1550 and Au1200 SMBus interface. + Au1550/Au1200/Au1300 SMBus interface. This driver can also be built as a module. If so, the module will be called i2c-au1550. diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index b6807db7b36f..e66d248fc126 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -132,7 +132,8 @@ #define ALI1535_SMBIO_EN 0x04 /* SMB I/O Space enable */ static struct pci_driver ali1535_driver; -static unsigned short ali1535_smba; +static unsigned long ali1535_smba; +static unsigned short ali1535_offset; /* Detect whether a ALI1535 can be found, and initialize it, where necessary. Note the differences between kernels with the old PCI BIOS interface and @@ -140,7 +141,7 @@ static unsigned short ali1535_smba; defined to make the transition easier. */ static int __devinit ali1535_setup(struct pci_dev *dev) { - int retval = -ENODEV; + int retval; unsigned char temp; /* Check the following things: @@ -149,15 +150,28 @@ static int __devinit ali1535_setup(struct pci_dev *dev) - We can use the addresses */ + retval = pci_enable_device(dev); + if (retval) { + dev_err(&dev->dev, "ALI1535_smb can't enable device\n"); + goto exit; + } + /* Determine the address of the SMBus area */ - pci_read_config_word(dev, SMBBA, &ali1535_smba); - ali1535_smba &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); - if (ali1535_smba == 0) { + pci_read_config_word(dev, SMBBA, &ali1535_offset); + dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset); + ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1)); + if (ali1535_offset == 0) { dev_warn(&dev->dev, "ALI1535_smb region uninitialized - upgrade BIOS?\n"); + retval = -ENODEV; goto exit; } + if (pci_resource_flags(dev, 0) & IORESOURCE_IO) + ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset; + else + ali1535_smba = ali1535_offset; + retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name); if (retval) @@ -165,8 +179,9 @@ static int __devinit ali1535_setup(struct pci_dev *dev) if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE, ali1535_driver.name)) { - dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n", + dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n", ali1535_smba); + retval = -EBUSY; goto exit; } @@ -174,6 +189,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBCFG, &temp); if ((temp & ALI1535_SMBIO_EN) == 0) { dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -181,6 +197,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBHSTCFG, &temp); if ((temp & 1) == 0) { dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -196,14 +213,13 @@ static int __devinit ali1535_setup(struct pci_dev *dev) */ pci_read_config_byte(dev, SMBREV, &temp); dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); - dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba); + dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba); - retval = 0; -exit: - return retval; + return 0; exit_free: release_region(ali1535_smba, ALI1535_SMB_IOSIZE); +exit: return retval; } @@ -498,7 +514,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ ali1535_adapter.dev.parent = &dev->dev; snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), - "SMBus ALI1535 adapter at %04x", ali1535_smba); + "SMBus ALI1535 adapter at %04x", ali1535_offset); return i2c_add_adapter(&ali1535_adapter); } diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index a409cfcf0629..47ae0091e027 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -417,7 +417,7 @@ static void __devexit ali1563_remove(struct pci_dev * dev) ali1563_shutdown(dev); } -static const struct pci_device_id ali1563_id_table[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) }, {}, }; diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index 83e8a60cdc86..087ea9caa74d 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -477,7 +477,7 @@ static struct i2c_adapter ali15x3_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id ali15x3_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 03bcd07c4697..eb778bf15c18 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -308,7 +308,7 @@ static const char* chipname[] = { "nVidia nForce", "AMD8111", }; -static const struct pci_device_id amd756_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B), .driver_data = AMD756 }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413), diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 6b6a6b1d7025..e5ac53b99b04 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -415,7 +415,7 @@ static const struct i2c_algorithm smbus_algorithm = { }; -static const struct pci_device_id amd8111_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 305c07504f7e..1679deef9c89 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -295,9 +295,6 @@ static int at91_i2c_resume(struct platform_device *pdev) #define at91_i2c_resume NULL #endif -/* work with "modprobe at91_i2c" from hotplugging or coldplugging */ -MODULE_ALIAS("platform:at91_i2c"); - static struct platform_driver at91_i2c_driver = { .probe = at91_i2c_probe, .remove = __devexit_p(at91_i2c_remove), @@ -309,19 +306,9 @@ static struct platform_driver at91_i2c_driver = { }, }; -static int __init at91_i2c_init(void) -{ - return platform_driver_register(&at91_i2c_driver); -} - -static void __exit at91_i2c_exit(void) -{ - platform_driver_unregister(&at91_i2c_driver); -} - -module_init(at91_i2c_init); -module_exit(at91_i2c_exit); +module_platform_driver(at91_i2c_driver); MODULE_AUTHOR("Rick Bronson"); MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:at91_i2c"); diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index f314d7f433d3..582d616db346 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -426,20 +426,9 @@ static struct platform_driver au1xpsc_smbus_driver = { .remove = __devexit_p(i2c_au1550_remove), }; -static int __init i2c_au1550_init(void) -{ - return platform_driver_register(&au1xpsc_smbus_driver); -} - -static void __exit i2c_au1550_exit(void) -{ - platform_driver_unregister(&au1xpsc_smbus_driver); -} +module_platform_driver(au1xpsc_smbus_driver); MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC."); MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:au1xpsc_smbus"); - -module_init (i2c_au1550_init); -module_exit (i2c_au1550_exit); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b1d9cd28d8da..c1e1096ba069 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -724,18 +724,7 @@ static struct platform_driver cpm_i2c_driver = { }, }; -static int __init cpm_i2c_init(void) -{ - return platform_driver_register(&cpm_i2c_driver); -} - -static void __exit cpm_i2c_exit(void) -{ - platform_driver_unregister(&cpm_i2c_driver); -} - -module_init(cpm_i2c_init); -module_exit(cpm_i2c_exit); +module_platform_driver(cpm_i2c_driver); MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>"); MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards"); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 9e89e7313d62..37f42113af31 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -349,7 +349,7 @@ static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("i2c_designware-pci"); -DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { +static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 18936ac9d51c..3ef3557b6e32 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -185,7 +185,7 @@ static DEFINE_MUTEX(pch_mutex); #define PCI_DEVICE_ID_ML7213_I2C 0x802D #define PCI_DEVICE_ID_ML7223_I2C 0x8010 -static struct pci_device_id __devinitdata pch_pcidev_id[] = { +static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, }, diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 63bb1cc2a042..19515df61021 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -52,7 +52,7 @@ struct highlander_i2c_dev { size_t buf_len; }; -static int iic_force_poll, iic_force_normal; +static bool iic_force_poll, iic_force_normal; static int iic_timeout = 1000, iic_read_delay; static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev) @@ -468,18 +468,7 @@ static struct platform_driver highlander_i2c_driver = { .remove = __devexit_p(highlander_i2c_remove), }; -static int __init highlander_i2c_init(void) -{ - return platform_driver_register(&highlander_i2c_driver); -} - -static void __exit highlander_i2c_exit(void) -{ - platform_driver_unregister(&highlander_i2c_driver); -} - -module_init(highlander_i2c_init); -module_exit(highlander_i2c_exit); +module_platform_driver(highlander_i2c_driver); MODULE_AUTHOR("Paul Mundt"); MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter"); diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c index 9ff1695d8458..c527de17db4f 100644 --- a/drivers/i2c/busses/i2c-hydra.c +++ b/drivers/i2c/busses/i2c-hydra.c @@ -105,7 +105,7 @@ static struct i2c_adapter hydra_adap = { .algo_data = &hydra_bit_data, }; -static const struct pci_device_id hydra_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ab26840d0c70..5d2e2816831f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -609,7 +609,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; -static const struct pci_device_id i801_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 3c110fbc409b..806e225f3de7 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -51,11 +51,11 @@ MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION); MODULE_LICENSE("GPL"); -static int iic_force_poll; +static bool iic_force_poll; module_param(iic_force_poll, bool, 0); MODULE_PARM_DESC(iic_force_poll, "Force polling mode"); -static int iic_force_fast; +static bool iic_force_fast; module_param(iic_force_fast, bool, 0); MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)"); @@ -815,15 +815,4 @@ static struct platform_driver ibm_iic_driver = { .remove = __devexit_p(iic_remove), }; -static int __init iic_init(void) -{ - return platform_driver_register(&ibm_iic_driver); -} - -static void __exit iic_exit(void) -{ - platform_driver_unregister(&ibm_iic_driver); -} - -module_init(iic_init); -module_exit(iic_exit); +module_platform_driver(ibm_iic_driver); diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index e828ac85cfa7..365bad5b890b 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -1093,7 +1093,7 @@ static void __devexit intel_mid_i2c_remove(struct pci_dev *dev) pci_release_region(dev, 0); } -static struct pci_device_id intel_mid_i2c_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = { /* Moorestown */ { PCI_VDEVICE(INTEL, 0x0802), 0 }, { PCI_VDEVICE(INTEL, 0x0803), 1 }, diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index f09c9319a2ba..93f147a96b62 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -523,21 +523,7 @@ static struct platform_driver iop3xx_i2c_driver = { }, }; -static int __init -i2c_iop3xx_init (void) -{ - return platform_driver_register(&iop3xx_i2c_driver); -} - -static void __exit -i2c_iop3xx_exit (void) -{ - platform_driver_unregister(&iop3xx_i2c_driver); - return; -} - -module_init (i2c_iop3xx_init); -module_exit (i2c_iop3xx_exit); +module_platform_driver(iop3xx_i2c_driver); MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>"); MODULE_DESCRIPTION("IOP3xx iic algorithm and driver"); diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 0682f8f277b0..6561d275b8cf 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -306,20 +306,9 @@ static struct platform_driver smbus_sch_driver = { .remove = __devexit_p(smbus_sch_remove), }; -static int __init i2c_sch_init(void) -{ - return platform_driver_register(&smbus_sch_driver); -} - -static void __exit i2c_sch_exit(void) -{ - platform_driver_unregister(&smbus_sch_driver); -} +module_platform_driver(smbus_sch_driver); MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>"); MODULE_DESCRIPTION("Intel SCH SMBus driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_sch_init); -module_exit(i2c_sch_exit); MODULE_ALIAS("platform:isch_smbus"); diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index c01e9519f6c1..5d263f9014d6 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -148,18 +148,7 @@ static struct platform_driver ixp2000_i2c_driver = { }, }; -static int __init ixp2000_i2c_init(void) -{ - return platform_driver_register(&ixp2000_i2c_driver); -} - -static void __exit ixp2000_i2c_exit(void) -{ - platform_driver_unregister(&ixp2000_i2c_driver); -} - -module_init(ixp2000_i2c_init); -module_exit(ixp2000_i2c_exit); +module_platform_driver(ixp2000_i2c_driver); MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>"); MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 107397a606b4..a8ebb84e23f9 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -715,18 +715,7 @@ static struct platform_driver mpc_i2c_driver = { }, }; -static int __init fsl_i2c_init(void) -{ - return platform_driver_register(&mpc_i2c_driver); -} - -static void __exit fsl_i2c_exit(void) -{ - platform_driver_unregister(&mpc_i2c_driver); -} - -module_init(fsl_i2c_init); -module_exit(fsl_i2c_exit); +module_platform_driver(mpc_i2c_driver); MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and " diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a9941c65f226..4f44a33017b0 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -611,20 +611,7 @@ static struct platform_driver mv64xxx_i2c_driver = { }, }; -static int __init -mv64xxx_i2c_init(void) -{ - return platform_driver_register(&mv64xxx_i2c_driver); -} - -static void __exit -mv64xxx_i2c_exit(void) -{ - platform_driver_unregister(&mv64xxx_i2c_driver); -} - -module_init(mv64xxx_i2c_init); -module_exit(mv64xxx_i2c_exit); +module_platform_driver(mv64xxx_i2c_driver); MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver"); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ff1e127dfea8..43a96a123920 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -309,7 +309,7 @@ static struct i2c_algorithm smbus_algorithm = { }; -static const struct pci_device_id nforce2_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) }, @@ -356,7 +356,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, error = acpi_check_region(smbus->base, smbus->size, nforce2_driver.name); if (error) - return -1; + return error; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1b46a9d9f907..18068dee48f1 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -394,9 +394,6 @@ static struct of_device_id ocores_i2c_match[] = { }; MODULE_DEVICE_TABLE(of, ocores_i2c_match); -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:ocores-i2c"); - static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, .remove = __devexit_p(ocores_i2c_remove), @@ -409,19 +406,9 @@ static struct platform_driver ocores_i2c_driver = { }, }; -static int __init ocores_i2c_init(void) -{ - return platform_driver_register(&ocores_i2c_driver); -} - -static void __exit ocores_i2c_exit(void) -{ - platform_driver_unregister(&ocores_i2c_driver); -} - -module_init(ocores_i2c_init); -module_exit(ocores_i2c_exit); +module_platform_driver(ocores_i2c_driver); MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); MODULE_DESCRIPTION("OpenCores I2C bus driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-i2c"); diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index 56dbe54e8811..ee139a598814 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -629,24 +629,10 @@ static struct platform_driver octeon_i2c_driver = { }, }; -static int __init octeon_i2c_init(void) -{ - int rv; - - rv = platform_driver_register(&octeon_i2c_driver); - return rv; -} - -static void __exit octeon_i2c_exit(void) -{ - platform_driver_unregister(&octeon_i2c_driver); -} +module_platform_driver(octeon_i2c_driver); MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_ALIAS("platform:" DRV_NAME); - -module_init(octeon_i2c_init); -module_exit(octeon_i2c_exit); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index 837b8c1aa02a..eaaea73209c5 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -401,7 +401,7 @@ static void __devexit pasemi_smb_remove(struct pci_dev *dev) kfree(smbus); } -static const struct pci_device_id pasemi_smb_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = { { PCI_DEVICE(0x1959, 0xa003) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index ace67995d7de..2adbf1a8fdea 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -286,20 +286,8 @@ static struct platform_driver i2c_pca_pf_driver = { }, }; -static int __init i2c_pca_pf_init(void) -{ - return platform_driver_register(&i2c_pca_pf_driver); -} - -static void __exit i2c_pca_pf_exit(void) -{ - platform_driver_unregister(&i2c_pca_pf_driver); -} +module_platform_driver(i2c_pca_pf_driver); MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver"); MODULE_LICENSE("GPL"); - -module_init(i2c_pca_pf_init); -module_exit(i2c_pca_pf_exit); - diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 6d14ac2e3c41..c14d48dd601a 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -472,7 +472,7 @@ static struct i2c_adapter piix4_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id piix4_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 127051b06921..07b7447ecbc9 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -627,9 +627,6 @@ static struct i2c_adapter pmcmsptwi_adapter = { .name = DRV_NAME, }; -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:" DRV_NAME); - static struct platform_driver pmcmsptwi_driver = { .probe = pmcmsptwi_probe, .remove = __devexit_p(pmcmsptwi_remove), @@ -639,18 +636,8 @@ static struct platform_driver pmcmsptwi_driver = { }, }; -static int __init pmcmsptwi_init(void) -{ - return platform_driver_register(&pmcmsptwi_driver); -} - -static void __exit pmcmsptwi_exit(void) -{ - platform_driver_unregister(&pmcmsptwi_driver); -} +module_platform_driver(pmcmsptwi_driver); MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver"); MODULE_LICENSE("GPL"); - -module_init(pmcmsptwi_init); -module_exit(pmcmsptwi_exit); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index b289ec99eeba..7b397c6f607e 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -312,10 +312,6 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) return rc; } - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:i2c-powermac"); - static struct platform_driver i2c_powermac_driver = { .probe = i2c_powermac_probe, .remove = __devexit_p(i2c_powermac_remove), @@ -325,17 +321,6 @@ static struct platform_driver i2c_powermac_driver = { }, }; -static int __init i2c_powermac_init(void) -{ - platform_driver_register(&i2c_powermac_driver); - return 0; -} +module_platform_driver(i2c_powermac_driver); - -static void __exit i2c_powermac_cleanup(void) -{ - platform_driver_unregister(&i2c_powermac_driver); -} - -module_init(i2c_powermac_init); -module_exit(i2c_powermac_cleanup); +MODULE_ALIAS("platform:i2c-powermac"); diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 632e088760a3..a05817980556 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -150,7 +150,7 @@ static void __devexit ce4100_i2c_remove(struct pci_dev *dev) kfree(sds); } -static struct pci_device_id ce4100_i2c_devices[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, { }, }; diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index a67132b2e092..c0c9dffbdb12 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -560,18 +560,7 @@ static struct platform_driver sh7760_i2c_drv = { .remove = __devexit_p(sh7760_i2c_remove), }; -static int __init sh7760_i2c_init(void) -{ - return platform_driver_register(&sh7760_i2c_drv); -} - -static void __exit sh7760_i2c_exit(void) -{ - platform_driver_unregister(&sh7760_i2c_drv); -} - -module_init(sh7760_i2c_init); -module_exit(sh7760_i2c_exit); +module_platform_driver(sh7760_i2c_drv); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 2fc08fbf67a2..4fc87e7c94c9 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -156,12 +156,8 @@ static int simtec_i2c_remove(struct platform_device *dev) return 0; } - /* device driver */ -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:simtec-i2c"); - static struct platform_driver simtec_i2c_driver = { .driver = { .name = "simtec-i2c", @@ -171,19 +167,9 @@ static struct platform_driver simtec_i2c_driver = { .remove = simtec_i2c_remove, }; -static int __init i2c_adap_simtec_init(void) -{ - return platform_driver_register(&simtec_i2c_driver); -} - -static void __exit i2c_adap_simtec_exit(void) -{ - platform_driver_unregister(&simtec_i2c_driver); -} - -module_init(i2c_adap_simtec_init); -module_exit(i2c_adap_simtec_exit); +module_platform_driver(simtec_i2c_driver); MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:simtec-i2c"); diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 437586611d4a..87e5126d449c 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -147,7 +147,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) u16 a; u8 val; int *i; - int retval = -ENODEV; + int retval; /* Look for imposters */ for (i = blacklist; *i != 0; i++) { @@ -223,7 +223,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) error: release_region(sis5595_base + SMB_INDEX, 2); - return retval; + return -ENODEV; } static int sis5595_transaction(struct i2c_adapter *adap) @@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis5595_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e6f539e26f65..15cf78f65ce0 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -93,8 +93,8 @@ static struct pci_driver sis630_driver; /* insmod parameters */ -static int high_clock; -static int force; +static bool high_clock; +static bool force; module_param(high_clock, bool, 0); MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); module_param(force, bool, 0); @@ -393,7 +393,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) { unsigned char b; struct pci_dev *dummy = NULL; - int retval = -ENODEV, i; + int retval, i; /* check for supported SiS devices */ for (i=0; supported[i] > 0 ; i++) { @@ -418,18 +418,21 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) */ if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) { dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n"); + retval = -ENODEV; goto exit; } /* if ACPI already enabled , do nothing */ if (!(b & 0x80) && pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) { dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n"); + retval = -ENODEV; goto exit; } /* Determine the ACPI base address */ if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) { dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n"); + retval = -ENODEV; goto exit; } @@ -445,6 +448,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) sis630_driver.name)) { dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); + retval = -EBUSY; goto exit; } @@ -468,7 +472,7 @@ static struct i2c_adapter sis630_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis630_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, { 0, } diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 86837f0c4cb9..cc5d149413f7 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -245,7 +245,7 @@ static struct i2c_adapter sis96x_adapter = { .algo = &smbus_algorithm, }; -static const struct pci_device_id sis96x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index 7799fe5bda88..713d31ade26b 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -89,7 +89,7 @@ static struct i2c_adapter vt586b_adapter = { }; -static const struct pci_device_id vt586b_ids[] __devinitconst = { +static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0b012f1f8ac5..333011c83d52 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -91,7 +91,7 @@ static unsigned short SMBHSTCFG = 0xD2; /* If force is set to anything different from 0, we forcibly enable the VT596. DANGEROUS! */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!"); @@ -324,7 +324,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, const struct pci_device_id *id) { unsigned char temp; - int error = -ENODEV; + int error; /* Determine the address of the SMBus areas */ if (force_addr) { @@ -390,6 +390,7 @@ found: dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " "controller not enabled! - upgrade BIOS or " "use force=1\n"); + error = -ENODEV; goto release_region; } } @@ -422,9 +423,11 @@ found: "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); - if (i2c_add_adapter(&vt596_adapter)) { + error = i2c_add_adapter(&vt596_adapter); + if (error) { pci_dev_put(vt596_pdev); vt596_pdev = NULL; + goto release_region; } /* Always return failure here. This is to allow other drivers to bind @@ -438,7 +441,7 @@ release_region: return error; } -static const struct pci_device_id vt596_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index ac083a28ae08..2bded7647ef2 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -795,10 +795,6 @@ static int __devexit xiic_i2c_remove(struct platform_device* pdev) return 0; } - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:"DRIVER_NAME); - static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, .remove = __devexit_p(xiic_i2c_remove), @@ -808,19 +804,9 @@ static struct platform_driver xiic_i2c_driver = { }, }; -static int __init xiic_i2c_init(void) -{ - return platform_driver_register(&xiic_i2c_driver); -} - -static void __exit xiic_i2c_exit(void) -{ - platform_driver_unregister(&xiic_i2c_driver); -} - -module_init(xiic_i2c_init); -module_exit(xiic_i2c_exit); +module_platform_driver(xiic_i2c_driver); MODULE_AUTHOR("info@mocean-labs.com"); MODULE_DESCRIPTION("Xilinx I2C bus driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 91e349c884c5..2eacb7784d56 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -559,7 +559,7 @@ static struct platform_driver scx200_pci_driver = { .remove = __devexit_p(scx200_remove), }; -static const struct pci_device_id scx200_isa[] __initconst = { +static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, { 0, } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 57a45ce84b2d..10e7f1e76586 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -251,15 +251,10 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; - rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); - if (!rdwr_pa) - return -ENOMEM; - - if (copy_from_user(rdwr_pa, rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { - kfree(rdwr_pa); - return -EFAULT; - } + rdwr_pa = memdup_user(rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + if (IS_ERR(rdwr_pa)) + return PTR_ERR(rdwr_pa); data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { diff --git a/drivers/i2c/muxes/gpio-i2cmux.c b/drivers/i2c/muxes/gpio-i2cmux.c index 7b6ce624cd6e..e5fa695eb0fa 100644 --- a/drivers/i2c/muxes/gpio-i2cmux.c +++ b/drivers/i2c/muxes/gpio-i2cmux.c @@ -165,18 +165,7 @@ static struct platform_driver gpiomux_driver = { }, }; -static int __init gpiomux_init(void) -{ - return platform_driver_register(&gpiomux_driver); -} - -static void __exit gpiomux_exit(void) -{ - platform_driver_unregister(&gpiomux_driver); -} - -module_init(gpiomux_init); -module_exit(gpiomux_exit); +module_platform_driver(gpiomux_driver); MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver"); MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>"); diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c index 25b9fe3a9f8e..d3be99fb4154 100644 --- a/drivers/ide/ali14xx.c +++ b/drivers/ide/ali14xx.c @@ -221,7 +221,7 @@ static int __init ali14xx_probe(void) return ide_legacy_device_add(&ali14xx_port_info, 0); } -static int probe_ali14xx; +static bool probe_ali14xx; module_param_named(probe, probe_ali14xx, bool, 0); MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets"); diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index a81bd7575792..14717304b388 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -111,7 +111,7 @@ #define DRV_NAME "cmd640" -static int cmd640_vlb; +static bool cmd640_vlb; /* * CMD640 specific registers definition. diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c index 6929f7fce93a..46af4743b3e6 100644 --- a/drivers/ide/dtc2278.c +++ b/drivers/ide/dtc2278.c @@ -130,7 +130,7 @@ static int __init dtc2278_probe(void) return ide_legacy_device_add(&dtc2278_port_info, 0); } -static int probe_dtc2278; +static bool probe_dtc2278; module_param_named(probe, probe_dtc2278, bool, 0); MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets"); diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c index 3feaa26410be..51beb85250d4 100644 --- a/drivers/ide/gayle.c +++ b/drivers/ide/gayle.c @@ -50,7 +50,7 @@ GAYLE_NUM_HWIFS-1) #define GAYLE_HAS_CONTROL_REG (!ide_doubler) -static int ide_doubler; +static bool ide_doubler; module_param_named(doubler, ide_doubler, bool, 0); MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c index 808bcdcbf8e1..986f2513eab4 100644 --- a/drivers/ide/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -317,7 +317,7 @@ static void __init ht6560b_init_dev(ide_drive_t *drive) ide_set_drivedata(drive, (void *)t); } -static int probe_ht6560b; +static bool probe_ht6560b; module_param_named(probe, probe_ht6560b, bool, 0); MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c index 979d342c338a..547d7cf2e016 100644 --- a/drivers/ide/ide-4drives.c +++ b/drivers/ide/ide-4drives.c @@ -6,7 +6,7 @@ #define DRV_NAME "ide-4drives" -static int probe_4drives; +static bool probe_4drives; module_param_named(probe, probe_4drives, bool, 0); MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port"); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index f22edc66b030..f1a6796b165c 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -53,15 +53,15 @@ struct ide_acpi_hwif_link { #define DEBPRINT(fmt, args...) do {} while (0) #endif /* DEBUGGING */ -static int ide_noacpi; +static bool ide_noacpi; module_param_named(noacpi, ide_noacpi, bool, 0); MODULE_PARM_DESC(noacpi, "disable IDE ACPI support"); -static int ide_acpigtf; +static bool ide_acpigtf; module_param_named(acpigtf, ide_acpigtf, bool, 0); MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support"); -static int ide_acpionboot; +static bool ide_acpionboot; module_param_named(acpionboot, ide_acpionboot, bool, 0); MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot"); diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c index d267b7affad6..a22ca8467010 100644 --- a/drivers/ide/ide-floppy_ioctl.c +++ b/drivers/ide/ide-floppy_ioctl.c @@ -292,8 +292,7 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, * and CDROM_SEND_PACKET (legacy) ioctls */ if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) - err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk, - mode, cmd, argp); + err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); if (err == -ENOTTY) err = generic_ide_ioctl(drive, bdev, cmd, arg); diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c index a743e68a8903..7f56b738d762 100644 --- a/drivers/ide/ide-pci-generic.c +++ b/drivers/ide/ide-pci-generic.c @@ -28,7 +28,7 @@ #define DRV_NAME "ide_pci_generic" -static int ide_generic_all; /* Set to claim all devices */ +static bool ide_generic_all; /* Set to claim all devices */ module_param_named(all_generic_ide, ide_generic_all, bool, 0444); MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers."); diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index 3f0244fd8e62..8bbfe5557c7b 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -417,7 +417,7 @@ static int __init qd_probe(int base) return rc; } -static int probe_qd65xx; +static bool probe_qd65xx; module_param_named(probe, probe_qd65xx, bool, 0); MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c index 47adcd09cb26..5cfb78120669 100644 --- a/drivers/ide/umc8672.c +++ b/drivers/ide/umc8672.c @@ -160,7 +160,7 @@ static int __init umc8672_probe(void) return ide_legacy_device_add(&umc8672_port_info, 0); } -static int probe_umc8672; +static bool probe_umc8672; module_param_named(probe, probe_umc8672, bool, 0); MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index aaf6023a4835..f08f6eaf3fa8 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -379,8 +379,8 @@ extern spinlock_t shca_list_lock; extern int ehca_static_rate; extern int ehca_port_act_time; -extern int ehca_use_hp_mr; -extern int ehca_scaling_code; +extern bool ehca_use_hp_mr; +extern bool ehca_scaling_code; extern int ehca_lock_hcalls; extern int ehca_nr_ports; extern int ehca_max_cq; diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index c240e9972cb0..832e7a7d0aee 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -59,16 +59,16 @@ MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); MODULE_VERSION(HCAD_VERSION); -static int ehca_open_aqp1 = 0; +static bool ehca_open_aqp1 = 0; static int ehca_hw_level = 0; -static int ehca_poll_all_eqs = 1; +static bool ehca_poll_all_eqs = 1; int ehca_debug_level = 0; int ehca_nr_ports = -1; -int ehca_use_hp_mr = 0; +bool ehca_use_hp_mr = 0; int ehca_port_act_time = 30; int ehca_static_rate = -1; -int ehca_scaling_code = 0; +bool ehca_scaling_code = 0; int ehca_lock_hcalls = -1; int ehca_max_cq = -1; int ehca_max_qp = -1; @@ -82,7 +82,7 @@ module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO); module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO); module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO); -module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); +module_param_named(lock_hcalls, ehca_lock_hcalls, bint, S_IRUGO); module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO); module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO); diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 5965b3df8f2f..7013da5e9eda 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -96,7 +96,7 @@ unsigned int wqm_quanta = 0x10000; module_param(wqm_quanta, int, 0644); MODULE_PARM_DESC(wqm_quanta, "WQM quanta"); -static unsigned int limit_maxrdreqsz; +static bool limit_maxrdreqsz; module_param(limit_maxrdreqsz, bool, 0644); MODULE_PARM_DESC(limit_maxrdreqsz, "Limit max read request size to 256 Bytes"); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 32bbd4c77b7c..fd7a0d5bc94d 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -98,15 +98,15 @@ #define XTYPE_XBOX360W 2 #define XTYPE_UNKNOWN 3 -static int dpad_to_buttons; +static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); -static int triggers_to_buttons; +static bool triggers_to_buttons; module_param(triggers_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads"); -static int sticks_to_null; +static bool sticks_to_null; module_param(sticks_to_null, bool, S_IRUGO); MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads"); diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index 79d901633635..350fd0c385d2 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -12,7 +12,7 @@ #include <linux/platform_device.h> #include <linux/input.h> #include <linux/interrupt.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/slab.h> /** diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 52b419348983..e2bdfd4bea70 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -48,7 +48,7 @@ MODULE_DESCRIPTION("Wistron laptop button driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("0.3"); -static int force; /* = 0; */ +static bool force; /* = 0; */ module_param(force, bool, 0); MODULE_PARM_DESC(force, "Load even if computer is not in database"); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index de7e8bc17b1f..e6c9931f02c7 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -60,7 +60,7 @@ static unsigned int psmouse_rate = 100; module_param_named(rate, psmouse_rate, uint, 0644); MODULE_PARM_DESC(rate, "Report rate, in reports per second."); -static unsigned int psmouse_smartscroll = 1; +static bool psmouse_smartscroll = 1; module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 4b755cb5b38c..1c58aafa523f 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -185,17 +185,17 @@ #define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4) /* Control touchpad's No Deceleration option */ -static int no_decel = 1; +static bool no_decel = 1; module_param(no_decel, bool, 0644); MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)"); /* Control touchpad's Reduced Reporting option */ -static int reduce_report; +static bool reduce_report; module_param(reduce_report, bool, 0644); MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)"); /* Control touchpad's No Filter option */ -static int no_filter; +static bool no_filter; module_param(no_filter, bool, 0644); MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)"); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 979c443bf1ef..be3316073ae7 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -105,7 +105,7 @@ EXPORT_SYMBOL(__hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_enqueue_transaction); EXPORT_SYMBOL(hp_sdc_dequeue_transaction); -static unsigned int hp_sdc_disabled; +static bool hp_sdc_disabled; module_param_named(no_hpsdc, hp_sdc_disabled, bool, 0); MODULE_PARM_DESC(no_hpsdc, "Do not enable HP SDC driver."); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 7f8f538a9806..1df19bb8534a 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -35,11 +35,11 @@ #include <linux/input/eeti_ts.h> #include <linux/slab.h> -static int flip_x; +static bool flip_x; module_param(flip_x, bool, 0644); MODULE_PARM_DESC(flip_x, "flip x coordinate"); -static int flip_y; +static bool flip_y; module_param(flip_y, bool, 0644); MODULE_PARM_DESC(flip_y, "flip y coordinate"); diff --git a/drivers/input/touchscreen/htcpen.c b/drivers/input/touchscreen/htcpen.c index 81e338623944..d13143b68b3e 100644 --- a/drivers/input/touchscreen/htcpen.c +++ b/drivers/input/touchscreen/htcpen.c @@ -40,10 +40,10 @@ MODULE_LICENSE("GPL"); #define X_AXIS_MAX 2040 #define Y_AXIS_MAX 2040 -static int invert_x; +static bool invert_x; module_param(invert_x, bool, 0644); MODULE_PARM_DESC(invert_x, "If set, X axis is inverted"); -static int invert_y; +static bool invert_y; module_param(invert_y, bool, 0644); MODULE_PARM_DESC(invert_y, "If set, Y axis is inverted"); diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index d2b57536feea..46e83ad53f43 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -30,7 +30,7 @@ #define UCB1400_TS_POLL_PERIOD 10 /* ms */ -static int adcsync; +static bool adcsync; static int ts_delay = 55; /* us */ static int ts_delay_pressure; /* us */ diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 06cef3ccc63a..3a5ebf452e81 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -60,11 +60,11 @@ #define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>" #define DRIVER_DESC "USB Touchscreen Driver" -static int swap_xy; +static bool swap_xy; module_param(swap_xy, bool, 0644); MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); -static int hwcalib_xy; +static bool hwcalib_xy; module_param(hwcalib_xy, bool, 0644); MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available"); diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 9c8d7aa053c5..a0ed668d4d2a 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -40,7 +40,7 @@ MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards"); MODULE_AUTHOR("Carsten Paeth"); MODULE_LICENSE("GPL"); -static int suppress_pollack = 0; +static bool suppress_pollack = 0; module_param(suppress_pollack, bool, 0); /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index d3530f6e8115..9743b24ef9d6 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -40,7 +40,7 @@ static char *revision = "$Revision: 1.1.2.2 $"; /* ------------------------------------------------------------- */ -static int suppress_pollack; +static bool suppress_pollack; static struct pci_device_id c4_pci_tbl[] = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 }, diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index 9c6650ea848e..2302fbe70ac6 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig @@ -6,7 +6,7 @@ if ISDN_I4L config ISDN_PPP bool "Support synchronous PPP" - depends on INET + depends on INET && NETDEVICES select SLHC help Over digital connections such as ISDN, there is no need to diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index ca710ab278ec..023de789f250 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -30,7 +30,7 @@ static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCo static unsigned int io[] = {0,0,0,0}; static unsigned char irq[] = {0,0,0,0}; static unsigned long ram[] = {0,0,0,0}; -static int do_reset = 0; +static bool do_reset = 0; module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 897a77dfa9d7..c957c344233f 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -396,6 +396,13 @@ config LEDS_TCA6507 LED driver chips accessed via the I2C bus. Driver support brightness control and hardware-assisted blinking. +config LEDS_MAX8997 + tristate "LED support for MAX8997 PMIC" + depends on LEDS_CLASS && MFD_MAX8997 + help + This option enables support for on-chip LED drivers on + MAXIM MAX8997 PMIC. + config LEDS_TRIGGERS bool "LED Trigger support" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 5c9dc4b000d5..b8a9723477f0 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_LEDS_NS2) += leds-ns2.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o +obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index a498135a4e80..1ed1677c916f 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -18,7 +18,7 @@ MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>"); MODULE_DESCRIPTION("Clevo mail LED driver"); MODULE_LICENSE("GPL"); -static unsigned int __initdata nodetect; +static bool __initdata nodetect; module_param_named(nodetect, nodetect, bool, 0); MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection"); diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c new file mode 100644 index 000000000000..f4c0e37fad1e --- /dev/null +++ b/drivers/leds/leds-max8997.c @@ -0,0 +1,372 @@ +/* + * leds-max8997.c - LED class driver for MAX8997 LEDs. + * + * Copyright (C) 2011 Samsung Electronics + * Donggeun Kim <dg77.kim@samsung.com> + * + * 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 <linux/module.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/leds.h> +#include <linux/mfd/max8997.h> +#include <linux/mfd/max8997-private.h> +#include <linux/platform_device.h> + +#define MAX8997_LED_FLASH_SHIFT 3 +#define MAX8997_LED_FLASH_CUR_MASK 0xf8 +#define MAX8997_LED_MOVIE_SHIFT 4 +#define MAX8997_LED_MOVIE_CUR_MASK 0xf0 + +#define MAX8997_LED_FLASH_MAX_BRIGHTNESS 0x1f +#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS 0xf +#define MAX8997_LED_NONE_MAX_BRIGHTNESS 0 + +#define MAX8997_LED0_FLASH_MASK 0x1 +#define MAX8997_LED0_FLASH_PIN_MASK 0x5 +#define MAX8997_LED0_MOVIE_MASK 0x8 +#define MAX8997_LED0_MOVIE_PIN_MASK 0x28 + +#define MAX8997_LED1_FLASH_MASK 0x2 +#define MAX8997_LED1_FLASH_PIN_MASK 0x6 +#define MAX8997_LED1_MOVIE_MASK 0x10 +#define MAX8997_LED1_MOVIE_PIN_MASK 0x30 + +#define MAX8997_LED_BOOST_ENABLE_MASK (1 << 6) + +struct max8997_led { + struct max8997_dev *iodev; + struct led_classdev cdev; + bool enabled; + int id; + enum max8997_led_mode led_mode; + struct mutex mutex; +}; + +static void max8997_led_clear_mode(struct max8997_led *led, + enum max8997_led_mode mode) +{ + struct i2c_client *client = led->iodev->i2c; + u8 val = 0, mask = 0; + int ret; + + switch (mode) { + case MAX8997_FLASH_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; + break; + case MAX8997_MOVIE_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; + break; + case MAX8997_FLASH_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; + break; + case MAX8997_MOVIE_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; + break; + default: + break; + } + + if (mask) { + ret = max8997_update_reg(client, + MAX8997_REG_LEN_CNTL, val, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + } +} + +static void max8997_led_set_mode(struct max8997_led *led, + enum max8997_led_mode mode) +{ + int ret; + struct i2c_client *client = led->iodev->i2c; + u8 mask = 0; + + /* First, clear the previous mode */ + max8997_led_clear_mode(led, led->led_mode); + + switch (mode) { + case MAX8997_FLASH_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; + led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; + break; + case MAX8997_MOVIE_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; + led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; + break; + case MAX8997_FLASH_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; + led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; + break; + case MAX8997_MOVIE_PIN_CONTROL_MODE: + mask = led->id ? + MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; + led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; + break; + default: + led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS; + break; + } + + if (mask) { + ret = max8997_update_reg(client, + MAX8997_REG_LEN_CNTL, mask, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + } + + led->led_mode = mode; +} + +static void max8997_led_enable(struct max8997_led *led, bool enable) +{ + int ret; + struct i2c_client *client = led->iodev->i2c; + u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK; + + if (led->enabled == enable) + return; + + val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0; + + ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + + led->enabled = enable; +} + +static void max8997_led_set_current(struct max8997_led *led, + enum led_brightness value) +{ + int ret; + struct i2c_client *client = led->iodev->i2c; + u8 val = 0, mask = 0, reg = 0; + + switch (led->led_mode) { + case MAX8997_FLASH_MODE: + case MAX8997_FLASH_PIN_CONTROL_MODE: + val = value << MAX8997_LED_FLASH_SHIFT; + mask = MAX8997_LED_FLASH_CUR_MASK; + reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR; + break; + case MAX8997_MOVIE_MODE: + case MAX8997_MOVIE_PIN_CONTROL_MODE: + val = value << MAX8997_LED_MOVIE_SHIFT; + mask = MAX8997_LED_MOVIE_CUR_MASK; + reg = MAX8997_REG_MOVIE_CUR; + break; + default: + break; + } + + if (mask) { + ret = max8997_update_reg(client, reg, val, mask); + if (ret) + dev_err(led->iodev->dev, + "failed to update register(%d)\n", ret); + } +} + +static void max8997_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct max8997_led *led = + container_of(led_cdev, struct max8997_led, cdev); + + if (value) { + max8997_led_set_current(led, value); + max8997_led_enable(led, true); + } else { + max8997_led_set_current(led, value); + max8997_led_enable(led, false); + } +} + +static ssize_t max8997_led_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct max8997_led *led = + container_of(led_cdev, struct max8997_led, cdev); + ssize_t ret = 0; + + mutex_lock(&led->mutex); + + switch (led->led_mode) { + case MAX8997_FLASH_MODE: + ret += sprintf(buf, "FLASH\n"); + break; + case MAX8997_MOVIE_MODE: + ret += sprintf(buf, "MOVIE\n"); + break; + case MAX8997_FLASH_PIN_CONTROL_MODE: + ret += sprintf(buf, "FLASH_PIN_CONTROL\n"); + break; + case MAX8997_MOVIE_PIN_CONTROL_MODE: + ret += sprintf(buf, "MOVIE_PIN_CONTROL\n"); + break; + default: + ret += sprintf(buf, "NONE\n"); + break; + } + + mutex_unlock(&led->mutex); + + return ret; +} + +static ssize_t max8997_led_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct max8997_led *led = + container_of(led_cdev, struct max8997_led, cdev); + enum max8997_led_mode mode; + + mutex_lock(&led->mutex); + + if (!strncmp(buf, "FLASH_PIN_CONTROL", 17)) + mode = MAX8997_FLASH_PIN_CONTROL_MODE; + else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17)) + mode = MAX8997_MOVIE_PIN_CONTROL_MODE; + else if (!strncmp(buf, "FLASH", 5)) + mode = MAX8997_FLASH_MODE; + else if (!strncmp(buf, "MOVIE", 5)) + mode = MAX8997_MOVIE_MODE; + else + mode = MAX8997_NONE; + + max8997_led_set_mode(led, mode); + + mutex_unlock(&led->mutex); + + return size; +} + +static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); + +static int __devinit max8997_led_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8997_led *led; + char name[20]; + int ret = 0; + + if (pdata == NULL) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (led == NULL) { + ret = -ENOMEM; + goto err_mem; + } + + led->id = pdev->id; + snprintf(name, sizeof(name), "max8997-led%d", pdev->id); + + led->cdev.name = name; + led->cdev.brightness_set = max8997_led_brightness_set; + led->cdev.flags |= LED_CORE_SUSPENDRESUME; + led->cdev.brightness = 0; + led->iodev = iodev; + + /* initialize mode and brightness according to platform_data */ + if (pdata->led_pdata) { + u8 mode = 0, brightness = 0; + + mode = pdata->led_pdata->mode[led->id]; + brightness = pdata->led_pdata->brightness[led->id]; + + max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]); + + if (brightness > led->cdev.max_brightness) + brightness = led->cdev.max_brightness; + max8997_led_set_current(led, brightness); + led->cdev.brightness = brightness; + } else { + max8997_led_set_mode(led, MAX8997_NONE); + max8997_led_set_current(led, 0); + } + + mutex_init(&led->mutex); + + platform_set_drvdata(pdev, led); + + ret = led_classdev_register(&pdev->dev, &led->cdev); + if (ret < 0) + goto err_led; + + ret = device_create_file(led->cdev.dev, &dev_attr_mode); + if (ret != 0) { + dev_err(&pdev->dev, + "failed to create file: %d\n", ret); + goto err_file; + } + + return 0; + +err_file: + led_classdev_unregister(&led->cdev); +err_led: + kfree(led); +err_mem: + return ret; +} + +static int __devexit max8997_led_remove(struct platform_device *pdev) +{ + struct max8997_led *led = platform_get_drvdata(pdev); + + device_remove_file(led->cdev.dev, &dev_attr_mode); + led_classdev_unregister(&led->cdev); + kfree(led); + + return 0; +} + +static struct platform_driver max8997_led_driver = { + .driver = { + .name = "max8997-led", + .owner = THIS_MODULE, + }, + .probe = max8997_led_probe, + .remove = __devexit_p(max8997_led_remove), +}; + +static int __init max8997_led_init(void) +{ + return platform_driver_register(&max8997_led_driver); +} +module_init(max8997_led_init); + +static void __exit max8997_led_exit(void) +{ + platform_driver_unregister(&max8997_led_driver); +} +module_exit(max8997_led_exit); + +MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); +MODULE_DESCRIPTION("MAX8997 LED driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:max8997-led"); diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 614ebebaaa28..57371e1485ab 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -79,7 +79,7 @@ static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id) return 1; } -static unsigned int __initdata nodetect; +static bool __initdata nodetect; module_param_named(nodetect, nodetect, bool, 0); MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection"); diff --git a/drivers/macintosh/ams/ams-core.c b/drivers/macintosh/ams/ams-core.c index 399beb1638d1..5c6a2d876562 100644 --- a/drivers/macintosh/ams/ams-core.c +++ b/drivers/macintosh/ams/ams-core.c @@ -31,7 +31,7 @@ /* There is only one motion sensor per machine */ struct ams ams_info; -static unsigned int verbose; +static bool verbose; module_param(verbose, bool, 0644); MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output"); diff --git a/drivers/macintosh/ams/ams-input.c b/drivers/macintosh/ams/ams-input.c index 8a712392cd38..b27e530a87a4 100644 --- a/drivers/macintosh/ams/ams-input.c +++ b/drivers/macintosh/ams/ams-input.c @@ -19,11 +19,11 @@ #include "ams.h" -static unsigned int joystick; +static bool joystick; module_param(joystick, bool, S_IRUGO); MODULE_PARM_DESC(joystick, "Enable the input class device on module load"); -static unsigned int invert; +static bool invert; module_param(invert, bool, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 02367308ff2e..c60d025044ee 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -52,7 +52,7 @@ static const char *sensor_location[3]; static int limit_adjust; static int fan_speed = -1; -static int verbose; +static bool verbose; MODULE_AUTHOR("Colin Leroy <colin@colino.net>"); MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index f84c08029b21..9fb18c147825 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -368,8 +368,17 @@ static int flakey_status(struct dm_target *ti, status_type_t type, static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct flakey_c *fc = ti->private; + struct dm_dev *dev = fc->dev; + int r = 0; - return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (fc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 3921e3bb43c1..9728839f844a 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -116,7 +116,17 @@ static int linear_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct linear_c *lc = (struct linear_c *) ti->private; - return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg); + struct dm_dev *dev = lc->dev; + int r = 0; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (lc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm, diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 5e0090ef4182..801d92d237cf 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1520,6 +1520,12 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, spin_unlock_irqrestore(&m->lock, flags); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 8e9132130142..63cc54289aff 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -699,7 +699,7 @@ static int validate_hardware_logical_block_alignment(struct dm_table *table, while (i < dm_table_get_num_targets(table)) { ti = dm_table_get_target(table, i++); - blk_set_default_limits(&ti_limits); + blk_set_stacking_limits(&ti_limits); /* combine all target devices' limits */ if (ti->type->iterate_devices) @@ -1221,10 +1221,10 @@ int dm_calculate_queue_limits(struct dm_table *table, struct queue_limits ti_limits; unsigned i = 0; - blk_set_default_limits(limits); + blk_set_stacking_limits(limits); while (i < dm_table_get_num_targets(table)) { - blk_set_default_limits(&ti_limits); + blk_set_stacking_limits(&ti_limits); ti = dm_table_get_target(table, i++); diff --git a/drivers/md/md.c b/drivers/md/md.c index da52acb60f52..9417ae2fa0bb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4666,6 +4666,7 @@ static int md_alloc(dev_t dev, char *name) mddev->queue->queuedata = mddev; blk_queue_make_request(mddev->queue, md_make_request); + blk_set_stacking_limits(&mddev->queue->limits); disk = alloc_disk(1 << shift); if (!disk) { diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 996302ae210e..4a6d5cef3964 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig @@ -26,7 +26,7 @@ config MEDIA_TUNER select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && EXPERIMENTAL select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE @@ -116,6 +116,13 @@ config MEDIA_TUNER_MT2060 help A driver for the silicon IF tuner MT2060 from Microtune. +config MEDIA_TUNER_MT2063 + tristate "Microtune MT2063 silicon IF tuner" + depends on VIDEO_MEDIA && I2C + default m if MEDIA_TUNER_CUSTOMISE + help + A driver for the silicon IF tuner MT2063 from Microtune. + config MEDIA_TUNER_MT2266 tristate "Microtune MT2266 silicon tuner" depends on VIDEO_MEDIA && I2C diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 196c12a55f9a..8295854ab94b 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c index 9883617b7862..cb2c98fbad1b 100644 --- a/drivers/media/common/tuners/max2165.c +++ b/drivers/media/common/tuners/max2165.c @@ -151,7 +151,7 @@ static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) { u8 val; - if (bw == BANDWIDTH_8_MHZ) + if (bw == 8000000) val = priv->bb_filter_8mhz_cfg; else val = priv->bb_filter_7mhz_cfg; @@ -257,39 +257,28 @@ static void max2165_debug_status(struct max2165_priv *priv) dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); } -static int max2165_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int max2165_set_params(struct dvb_frontend *fe) { struct max2165_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency); - if (fe->ops.info.type == FE_ATSC) { - return -EINVAL; - } else if (fe->ops.info.type == FE_OFDM) { - dprintk("%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - return -EINVAL; - case BANDWIDTH_7_MHZ: - case BANDWIDTH_8_MHZ: - priv->frequency = params->frequency; - priv->bandwidth = params->u.ofdm.bandwidth; - break; - default: - printk(KERN_ERR "MAX2165 bandwidth not set!\n"); - return -EINVAL; - } - } else { - printk(KERN_ERR "MAX2165 modulation type not supported!\n"); + switch (c->bandwidth_hz) { + case 7000000: + case 8000000: + priv->frequency = c->frequency; + break; + default: + printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n", + c->bandwidth_hz); return -EINVAL; } - dprintk("%s() frequency=%d\n", __func__, priv->frequency); + dprintk("%s() frequency=%d\n", __func__, c->frequency); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - max2165_set_bandwidth(priv, priv->bandwidth); + max2165_set_bandwidth(priv, c->bandwidth_hz); ret = max2165_set_rf(priv, priv->frequency); mdelay(50); max2165_debug_status(priv); @@ -370,7 +359,7 @@ static int max2165_init(struct dvb_frontend *fe) max2165_read_rom_table(priv); - max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ); + max2165_set_bandwidth(priv, 8000000); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); diff --git a/drivers/media/common/tuners/mc44s803.c b/drivers/media/common/tuners/mc44s803.c index fe5c4b8d83ee..5ddce7e326f7 100644 --- a/drivers/media/common/tuners/mc44s803.c +++ b/drivers/media/common/tuners/mc44s803.c @@ -214,22 +214,22 @@ exit: return err; } -static int mc44s803_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mc44s803_set_params(struct dvb_frontend *fe) { struct mc44s803_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 r1, r2, n1, n2, lo1, lo2, freq, val; int err; - priv->frequency = params->frequency; + priv->frequency = c->frequency; r1 = MC44S803_OSC / 1000000; r2 = MC44S803_OSC / 100000; - n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000; + n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000; freq = MC44S803_OSC / r1 * n1; lo1 = ((60 * n1) + (r1 / 2)) / r1; - freq = freq - params->frequency; + freq = freq - c->frequency; n2 = (freq - MC44S803_IF2 + 50000) / 100000; lo2 = ((60 * n2) + (r2 / 2)) / r2; diff --git a/drivers/media/common/tuners/mt2060.c b/drivers/media/common/tuners/mt2060.c index 2d0e7689c6a2..13381de58a84 100644 --- a/drivers/media/common/tuners/mt2060.c +++ b/drivers/media/common/tuners/mt2060.c @@ -153,8 +153,9 @@ static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) #define IF2 36150 // IF2 frequency = 36.150 MHz #define FREF 16000 // Quartz oscillator 16 MHz -static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2060_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2060_priv *priv; int ret=0; int i=0; @@ -176,8 +177,7 @@ static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame mt2060_writeregs(priv,b,2); - freq = params->frequency / 1000; // Hz -> kHz - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + freq = c->frequency / 1000; /* Hz -> kHz */ f_lo1 = freq + if1 * 1000; f_lo1 = (f_lo1 / 250) * 250; @@ -293,10 +293,9 @@ static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct mt2060_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; + *frequency = IF2 * 1000; return 0; } @@ -356,7 +355,7 @@ static const struct dvb_tuner_ops mt2060_tuner_ops = { .set_params = mt2060_set_params, .get_frequency = mt2060_get_frequency, - .get_bandwidth = mt2060_get_bandwidth + .get_if_frequency = mt2060_get_if_frequency, }; /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ diff --git a/drivers/media/common/tuners/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h index 5eaccdefd0b0..2b60de6c707d 100644 --- a/drivers/media/common/tuners/mt2060_priv.h +++ b/drivers/media/common/tuners/mt2060_priv.h @@ -97,7 +97,6 @@ struct mt2060_priv { struct i2c_adapter *i2c; u32 frequency; - u32 bandwidth; u16 if1_freq; u8 fmfreq; }; diff --git a/drivers/media/common/tuners/mt2063.c b/drivers/media/common/tuners/mt2063.c new file mode 100644 index 000000000000..c89af3cd5eba --- /dev/null +++ b/drivers/media/common/tuners/mt2063.c @@ -0,0 +1,2307 @@ +/* + * Driver for mt2063 Micronas tuner + * + * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com> + * + * This driver came from a driver originally written by: + * Henry Wang <Henry.wang@AzureWave.com> + * Made publicly available by Terratec, at: + * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz + * The original driver's license is GPL, as declared with MODULE_LICENSE() + * + * 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 under version 2 of the License. + * + * 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 <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/videodev2.h> + +#include "mt2063.h" + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Set Verbosity level"); + +#define dprintk(level, fmt, arg...) do { \ +if (debug >= level) \ + printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ +} while (0) + + +/* positive error codes used internally */ + +/* Info: Unavoidable LO-related spur may be present in the output */ +#define MT2063_SPUR_PRESENT_ERR (0x00800000) + +/* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ +#define MT2063_SPUR_CNT_MASK (0x001f0000) +#define MT2063_SPUR_SHIFT (16) + +/* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ +#define MT2063_UPC_RANGE (0x04000000) + +/* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ +#define MT2063_DNC_RANGE (0x08000000) + +/* + * Constant defining the version of the following structure + * and therefore the API for this code. + * + * When compiling the tuner driver, the preprocessor will + * check against this version number to make sure that + * it matches the version that the tuner driver knows about. + */ + +/* DECT Frequency Avoidance */ +#define MT2063_DECT_AVOID_US_FREQS 0x00000001 + +#define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 + +#define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) + +#define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) + +enum MT2063_DECT_Avoid_Type { + MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ + MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ + MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ + MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ +}; + +#define MT2063_MAX_ZONES 48 + +struct MT2063_ExclZone_t { + u32 min_; + u32 max_; + struct MT2063_ExclZone_t *next_; +}; + +/* + * Structure of data needed for Spur Avoidance + */ +struct MT2063_AvoidSpursData_t { + u32 f_ref; + u32 f_in; + u32 f_LO1; + u32 f_if1_Center; + u32 f_if1_Request; + u32 f_if1_bw; + u32 f_LO2; + u32 f_out; + u32 f_out_bw; + u32 f_LO1_Step; + u32 f_LO2_Step; + u32 f_LO1_FracN_Avoid; + u32 f_LO2_FracN_Avoid; + u32 f_zif_bw; + u32 f_min_LO_Separation; + u32 maxH1; + u32 maxH2; + enum MT2063_DECT_Avoid_Type avoidDECT; + u32 bSpurPresent; + u32 bSpurAvoided; + u32 nSpursFound; + u32 nZones; + struct MT2063_ExclZone_t *freeZones; + struct MT2063_ExclZone_t *usedZones; + struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; +}; + +/* + * Parameter for function MT2063_SetPowerMask that specifies the power down + * of various sections of the MT2063. + */ +enum MT2063_Mask_Bits { + MT2063_REG_SD = 0x0040, /* Shutdown regulator */ + MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ + MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ + MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ + MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ + MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ + MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ + MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ + MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ + MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ + MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ + MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ + MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ + MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ + MT2063_NONE_SD = 0x0000 /* No shutdown bits */ +}; + +/* + * Possible values for MT2063_DNC_OUTPUT + */ +enum MT2063_DNC_Output_Enable { + MT2063_DNC_NONE = 0, + MT2063_DNC_1, + MT2063_DNC_2, + MT2063_DNC_BOTH +}; + +/* + * Two-wire serial bus subaddresses of the tuner registers. + * Also known as the tuner's register addresses. + */ +enum MT2063_Register_Offsets { + MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ + MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ + MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ + MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ + MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ + MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ + MT2063_REG_RSVD_06, /* 0x06: Reserved */ + MT2063_REG_LO_STATUS, /* 0x07: LO Status */ + MT2063_REG_FIFFC, /* 0x08: FIFF Center */ + MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ + MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ + MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ + MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ + MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ + MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ + MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ + MT2063_REG_RSVD_10, /* 0x10: Reserved */ + MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ + MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ + MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ + MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ + MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ + MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ + MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ + MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ + MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ + MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ + MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ + MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ + MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ + MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ + MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ + MT2063_REG_RSVD_20, /* 0x20: Reserved */ + MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ + MT2063_REG_RSVD_22, /* 0x22: Reserved */ + MT2063_REG_RSVD_23, /* 0x23: Reserved */ + MT2063_REG_RSVD_24, /* 0x24: Reserved */ + MT2063_REG_RSVD_25, /* 0x25: Reserved */ + MT2063_REG_RSVD_26, /* 0x26: Reserved */ + MT2063_REG_RSVD_27, /* 0x27: Reserved */ + MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ + MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ + MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ + MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ + MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ + MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ + MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ + MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ + MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ + MT2063_REG_RSVD_31, /* 0x31: Reserved */ + MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ + MT2063_REG_RSVD_33, /* 0x33: Reserved */ + MT2063_REG_RSVD_34, /* 0x34: Reserved */ + MT2063_REG_RSVD_35, /* 0x35: Reserved */ + MT2063_REG_RSVD_36, /* 0x36: Reserved */ + MT2063_REG_RSVD_37, /* 0x37: Reserved */ + MT2063_REG_RSVD_38, /* 0x38: Reserved */ + MT2063_REG_RSVD_39, /* 0x39: Reserved */ + MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ + MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ + MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ + MT2063_REG_END_REGS +}; + +struct mt2063_state { + struct i2c_adapter *i2c; + + bool init; + + const struct mt2063_config *config; + struct dvb_tuner_ops ops; + struct dvb_frontend *frontend; + struct tuner_state status; + + u32 frequency; + u32 srate; + u32 bandwidth; + u32 reference; + + u32 tuner_id; + struct MT2063_AvoidSpursData_t AS_Data; + u32 f_IF1_actual; + u32 rcvr_mode; + u32 ctfilt_sw; + u32 CTFiltMax[31]; + u32 num_regs; + u8 reg[MT2063_REG_END_REGS]; +}; + +/* + * mt2063_write - Write data into the I2C bus + */ +static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) +{ + struct dvb_frontend *fe = state->frontend; + int ret; + u8 buf[60]; + struct i2c_msg msg = { + .addr = state->config->tuner_address, + .flags = 0, + .buf = buf, + .len = len + 1 + }; + + dprintk(2, "\n"); + + msg.buf[0] = reg; + memcpy(msg.buf + 1, data, len); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + ret = i2c_transfer(state->i2c, &msg, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (ret < 0) + printk(KERN_ERR "%s error ret=%d\n", __func__, ret); + + return ret; +} + +/* + * mt2063_write - Write register data into the I2C bus, caching the value + */ +static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) +{ + u32 status; + + dprintk(2, "\n"); + + if (reg >= MT2063_REG_END_REGS) + return -ERANGE; + + status = mt2063_write(state, reg, &val, 1); + if (status < 0) + return status; + + state->reg[reg] = val; + + return 0; +} + +/* + * mt2063_read - Read data from the I2C bus + */ +static u32 mt2063_read(struct mt2063_state *state, + u8 subAddress, u8 *pData, u32 cnt) +{ + u32 status = 0; /* Status to be returned */ + struct dvb_frontend *fe = state->frontend; + u32 i = 0; + + dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + for (i = 0; i < cnt; i++) { + u8 b0[] = { subAddress + i }; + struct i2c_msg msg[] = { + { + .addr = state->config->tuner_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->tuner_address, + .flags = I2C_M_RD, + .buf = pData + i, + .len = 1 + } + }; + + status = i2c_transfer(state->i2c, msg, 2); + dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", + subAddress + i, status, *(pData + i)); + if (status < 0) + break; + } + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (status < 0) + printk(KERN_ERR "Can't read from address 0x%02x,\n", + subAddress + i); + + return status; +} + +/* + * FIXME: Is this really needed? + */ +static int MT2063_Sleep(struct dvb_frontend *fe) +{ + /* + * ToDo: Add code here to implement a OS blocking + */ + msleep(10); + + return 0; +} + +/* + * Microtune spur avoidance + */ + +/* Implement ceiling, floor functions. */ +#define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) +#define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) + +struct MT2063_FIFZone_t { + s32 min_; + s32 max_; +}; + +static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t + *pAS_Info, + struct MT2063_ExclZone_t *pPrevNode) +{ + struct MT2063_ExclZone_t *pNode; + + dprintk(2, "\n"); + + /* Check for a node in the free list */ + if (pAS_Info->freeZones != NULL) { + /* Use one from the free list */ + pNode = pAS_Info->freeZones; + pAS_Info->freeZones = pNode->next_; + } else { + /* Grab a node from the array */ + pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; + } + + if (pPrevNode != NULL) { + pNode->next_ = pPrevNode->next_; + pPrevNode->next_ = pNode; + } else { /* insert at the beginning of the list */ + + pNode->next_ = pAS_Info->usedZones; + pAS_Info->usedZones = pNode; + } + + pAS_Info->nZones++; + return pNode; +} + +static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t + *pAS_Info, + struct MT2063_ExclZone_t *pPrevNode, + struct MT2063_ExclZone_t + *pNodeToRemove) +{ + struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; + + dprintk(2, "\n"); + + /* Make previous node point to the subsequent node */ + if (pPrevNode != NULL) + pPrevNode->next_ = pNext; + + /* Add pNodeToRemove to the beginning of the freeZones */ + pNodeToRemove->next_ = pAS_Info->freeZones; + pAS_Info->freeZones = pNodeToRemove; + + /* Decrement node count */ + pAS_Info->nZones--; + + return pNext; +} + +/* + * MT_AddExclZone() + * + * Add (and merge) an exclusion zone into the list. + * If the range (f_min, f_max) is totally outside the + * 1st IF BW, ignore the entry. + * If the range (f_min, f_max) is negative, ignore the entry. + */ +static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, + u32 f_min, u32 f_max) +{ + struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; + struct MT2063_ExclZone_t *pPrev = NULL; + struct MT2063_ExclZone_t *pNext = NULL; + + dprintk(2, "\n"); + + /* Check to see if this overlaps the 1st IF filter */ + if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) + && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) + && (f_min < f_max)) { + /* + * 1 2 3 4 5 6 + * + * New entry: |---| |--| |--| |-| |---| |--| + * or or or or or + * Existing: |--| |--| |--| |---| |-| |--| + */ + + /* Check for our place in the list */ + while ((pNode != NULL) && (pNode->max_ < f_min)) { + pPrev = pNode; + pNode = pNode->next_; + } + + if ((pNode != NULL) && (pNode->min_ < f_max)) { + /* Combine me with pNode */ + if (f_min < pNode->min_) + pNode->min_ = f_min; + if (f_max > pNode->max_) + pNode->max_ = f_max; + } else { + pNode = InsertNode(pAS_Info, pPrev); + pNode->min_ = f_min; + pNode->max_ = f_max; + } + + /* Look for merging possibilities */ + pNext = pNode->next_; + while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { + if (pNext->max_ > pNode->max_) + pNode->max_ = pNext->max_; + /* Remove pNext, return ptr to pNext->next */ + pNext = RemoveNode(pAS_Info, pNode, pNext); + } + } +} + +/* + * Reset all exclusion zones. + * Add zones to protect the PLL FracN regions near zero + */ +static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + u32 center; + + dprintk(2, "\n"); + + pAS_Info->nZones = 0; /* this clears the used list */ + pAS_Info->usedZones = NULL; /* reset ptr */ + pAS_Info->freeZones = NULL; /* reset ptr */ + + center = + pAS_Info->f_ref * + ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + + pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; + while (center < + pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + + pAS_Info->f_LO1_FracN_Avoid) { + /* Exclude LO1 FracN */ + MT2063_AddExclZone(pAS_Info, + center - pAS_Info->f_LO1_FracN_Avoid, + center - 1); + MT2063_AddExclZone(pAS_Info, center + 1, + center + pAS_Info->f_LO1_FracN_Avoid); + center += pAS_Info->f_ref; + } + + center = + pAS_Info->f_ref * + ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - + pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; + while (center < + pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + + pAS_Info->f_LO2_FracN_Avoid) { + /* Exclude LO2 FracN */ + MT2063_AddExclZone(pAS_Info, + center - pAS_Info->f_LO2_FracN_Avoid, + center - 1); + MT2063_AddExclZone(pAS_Info, center + 1, + center + pAS_Info->f_LO2_FracN_Avoid); + center += pAS_Info->f_ref; + } + + if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { + /* Exclude LO1 values that conflict with DECT channels */ + MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ + MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ + MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ + MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ + MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ + } + + if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { + MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ + MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ + MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ + MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ + MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ + MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ + MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ + MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ + MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ + MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ + } +} + +/* + * MT_ChooseFirstIF - Choose the best available 1st IF + * If f_Desired is not excluded, choose that first. + * Otherwise, return the value closest to f_Center that is + * not excluded + */ +static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + /* + * Update "f_Desired" to be the nearest "combinational-multiple" of + * "f_LO1_Step". + * The resulting number, F_LO1 must be a multiple of f_LO1_Step. + * And F_LO1 is the arithmetic sum of f_in + f_Center. + * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. + * However, the sum must be. + */ + const u32 f_Desired = + pAS_Info->f_LO1_Step * + ((pAS_Info->f_if1_Request + pAS_Info->f_in + + pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - + pAS_Info->f_in; + const u32 f_Step = + (pAS_Info->f_LO1_Step > + pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> + f_LO2_Step; + u32 f_Center; + s32 i; + s32 j = 0; + u32 bDesiredExcluded = 0; + u32 bZeroExcluded = 0; + s32 tmpMin, tmpMax; + s32 bestDiff; + struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; + struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; + + dprintk(2, "\n"); + + if (pAS_Info->nZones == 0) + return f_Desired; + + /* + * f_Center needs to be an integer multiple of f_Step away + * from f_Desired + */ + if (pAS_Info->f_if1_Center > f_Desired) + f_Center = + f_Desired + + f_Step * + ((pAS_Info->f_if1_Center - f_Desired + + f_Step / 2) / f_Step); + else + f_Center = + f_Desired - + f_Step * + ((f_Desired - pAS_Info->f_if1_Center + + f_Step / 2) / f_Step); + + /* + * Take MT_ExclZones, center around f_Center and change the + * resolution to f_Step + */ + while (pNode != NULL) { + /* floor function */ + tmpMin = + floor((s32) (pNode->min_ - f_Center), (s32) f_Step); + + /* ceil function */ + tmpMax = + ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); + + if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) + bDesiredExcluded = 1; + + if ((tmpMin < 0) && (tmpMax > 0)) + bZeroExcluded = 1; + + /* See if this zone overlaps the previous */ + if ((j > 0) && (tmpMin < zones[j - 1].max_)) + zones[j - 1].max_ = tmpMax; + else { + /* Add new zone */ + zones[j].min_ = tmpMin; + zones[j].max_ = tmpMax; + j++; + } + pNode = pNode->next_; + } + + /* + * If the desired is okay, return with it + */ + if (bDesiredExcluded == 0) + return f_Desired; + + /* + * If the desired is excluded and the center is okay, return with it + */ + if (bZeroExcluded == 0) + return f_Center; + + /* Find the value closest to 0 (f_Center) */ + bestDiff = zones[0].min_; + for (i = 0; i < j; i++) { + if (abs(zones[i].min_) < abs(bestDiff)) + bestDiff = zones[i].min_; + if (abs(zones[i].max_) < abs(bestDiff)) + bestDiff = zones[i].max_; + } + + if (bestDiff < 0) + return f_Center - ((u32) (-bestDiff) * f_Step); + + return f_Center + (bestDiff * f_Step); +} + +/** + * gcd() - Uses Euclid's algorithm + * + * @u, @v: Unsigned values whose GCD is desired. + * + * Returns THE greatest common divisor of u and v, if either value is 0, + * the other value is returned as the result. + */ +static u32 MT2063_gcd(u32 u, u32 v) +{ + u32 r; + + while (v != 0) { + r = u % v; + u = v; + v = r; + } + + return u; +} + +/** + * IsSpurInBand() - Checks to see if a spur will be present within the IF's + * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) + * + * ma mb mc md + * <--+-+-+-------------------+-------------------+-+-+--> + * | ^ 0 ^ | + * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ + * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 + * + * Note that some equations are doubled to prevent round-off + * problems when calculating fIFBW/2 + * + * @pAS_Info: Avoid Spurs information block + * @fm: If spur, amount f_IF1 has to move negative + * @fp: If spur, amount f_IF1 has to move positive + * + * Returns 1 if an LO spur would be present, otherwise 0. + */ +static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, + u32 *fm, u32 * fp) +{ + /* + ** Calculate LO frequency settings. + */ + u32 n, n0; + const u32 f_LO1 = pAS_Info->f_LO1; + const u32 f_LO2 = pAS_Info->f_LO2; + const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; + const u32 c = d - pAS_Info->f_out_bw; + const u32 f = pAS_Info->f_zif_bw / 2; + const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; + s32 f_nsLO1, f_nsLO2; + s32 f_Spur; + u32 ma, mb, mc, md, me, mf; + u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; + + dprintk(2, "\n"); + + *fm = 0; + + /* + ** For each edge (d, c & f), calculate a scale, based on the gcd + ** of f_LO1, f_LO2 and the edge value. Use the larger of this + ** gcd-based scale factor or f_Scale. + */ + lo_gcd = MT2063_gcd(f_LO1, f_LO2); + gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); + hgds = gd_Scale / 2; + gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); + hgcs = gc_Scale / 2; + gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); + hgfs = gf_Scale / 2; + + n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); + + /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ + for (n = n0; n <= pAS_Info->maxH1; ++n) { + md = (n * ((f_LO1 + hgds) / gd_Scale) - + ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); + + /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ + if (md >= pAS_Info->maxH1) + break; + + ma = (n * ((f_LO1 + hgds) / gd_Scale) + + ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); + + /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ + if (md == ma) + continue; + + mc = (n * ((f_LO1 + hgcs) / gc_Scale) - + ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); + if (mc != md) { + f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); + f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); + f_Spur = + (gc_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); + + *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; + *fm = (((s32) d - f_Spur) / (mc - n)) + 1; + return 1; + } + + /* Location of Zero-IF-spur to be checked */ + me = (n * ((f_LO1 + hgfs) / gf_Scale) + + ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); + mf = (n * ((f_LO1 + hgfs) / gf_Scale) - + ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); + if (me != mf) { + f_nsLO1 = n * (f_LO1 / gf_Scale); + f_nsLO2 = me * (f_LO2 / gf_Scale); + f_Spur = + (gf_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); + + *fp = ((f_Spur + (s32) f) / (me - n)) + 1; + *fm = (((s32) f - f_Spur) / (me - n)) + 1; + return 1; + } + + mb = (n * ((f_LO1 + hgcs) / gc_Scale) + + ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); + if (ma != mb) { + f_nsLO1 = n * (f_LO1 / gc_Scale); + f_nsLO2 = ma * (f_LO2 / gc_Scale); + f_Spur = + (gc_Scale * (f_nsLO1 - f_nsLO2)) + + n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); + + *fp = (((s32) d + f_Spur) / (ma - n)) + 1; + *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; + return 1; + } + } + + /* No spurs found */ + return 0; +} + +/* + * MT_AvoidSpurs() - Main entry point to avoid spurs. + * Checks for existing spurs in present LO1, LO2 freqs + * and if present, chooses spur-free LO1, LO2 combination + * that tunes the same input/output frequencies. + */ +static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) +{ + u32 status = 0; + u32 fm, fp; /* restricted range on LO's */ + pAS_Info->bSpurAvoided = 0; + pAS_Info->nSpursFound = 0; + + dprintk(2, "\n"); + + if (pAS_Info->maxH1 == 0) + return 0; + + /* + * Avoid LO Generated Spurs + * + * Make sure that have no LO-related spurs within the IF output + * bandwidth. + * + * If there is an LO spur in this band, start at the current IF1 frequency + * and work out until we find a spur-free frequency or run up against the + * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they + * will be unchanged if a spur-free setting is not found. + */ + pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); + if (pAS_Info->bSpurPresent) { + u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ + u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ + u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ + u32 delta_IF1; + u32 new_IF1; + + /* + ** Spur was found, attempt to find a spur-free 1st IF + */ + do { + pAS_Info->nSpursFound++; + + /* Raise f_IF1_upper, if needed */ + MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); + + /* Choose next IF1 that is closest to f_IF1_CENTER */ + new_IF1 = MT2063_ChooseFirstIF(pAS_Info); + + if (new_IF1 > zfIF1) { + pAS_Info->f_LO1 += (new_IF1 - zfIF1); + pAS_Info->f_LO2 += (new_IF1 - zfIF1); + } else { + pAS_Info->f_LO1 -= (zfIF1 - new_IF1); + pAS_Info->f_LO2 -= (zfIF1 - new_IF1); + } + zfIF1 = new_IF1; + + if (zfIF1 > pAS_Info->f_if1_Center) + delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; + else + delta_IF1 = pAS_Info->f_if1_Center - zfIF1; + + pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); + /* + * Continue while the new 1st IF is still within the 1st IF bandwidth + * and there is a spur in the band (again) + */ + } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); + + /* + * Use the LO-spur free values found. If the search went all + * the way to the 1st IF band edge and always found spurs, just + * leave the original choice. It's as "good" as any other. + */ + if (pAS_Info->bSpurPresent == 1) { + status |= MT2063_SPUR_PRESENT_ERR; + pAS_Info->f_LO1 = zfLO1; + pAS_Info->f_LO2 = zfLO2; + } else + pAS_Info->bSpurAvoided = 1; + } + + status |= + ((pAS_Info-> + nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); + + return status; +} + +/* + * Constants used by the tuning algorithm + */ +#define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ +#define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ +#define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ +#define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ +#define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ +#define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ +#define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ +#define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ +#define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ +#define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ +#define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ +#define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ +#define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ +#define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ +#define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ +#define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ +#define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ +#define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ + +/* + * Define the supported Part/Rev codes for the MT2063 + */ +#define MT2063_B0 (0x9B) +#define MT2063_B1 (0x9C) +#define MT2063_B2 (0x9D) +#define MT2063_B3 (0x9E) + +/** + * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked + * + * @state: struct mt2063_state pointer + * + * This function returns 0, if no lock, 1 if locked and a value < 1 if error + */ +static unsigned int mt2063_lockStatus(struct mt2063_state *state) +{ + const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ + const u32 nPollRate = 2; /* poll status bits every 2 ms */ + const u32 nMaxLoops = nMaxWait / nPollRate; + const u8 LO1LK = 0x80; + u8 LO2LK = 0x08; + u32 status; + u32 nDelays = 0; + + dprintk(2, "\n"); + + /* LO2 Lock bit was in a different place for B0 version */ + if (state->tuner_id == MT2063_B0) + LO2LK = 0x40; + + do { + status = mt2063_read(state, MT2063_REG_LO_STATUS, + &state->reg[MT2063_REG_LO_STATUS], 1); + + if (status < 0) + return status; + + if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == + (LO1LK | LO2LK)) { + return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; + } + msleep(nPollRate); /* Wait between retries */ + } while (++nDelays < nMaxLoops); + + /* + * Got no lock or partial lock + */ + return 0; +} + +/* + * Constants for setting receiver modes. + * (6 modes defined at this time, enumerated by mt2063_delivery_sys) + * (DNC1GC & DNC2GC are the values, which are used, when the specific + * DNC Output is selected, the other is always off) + * + * enum mt2063_delivery_sys + * -------------+---------------------------------------------- + * Mode 0 : | MT2063_CABLE_QAM + * Mode 1 : | MT2063_CABLE_ANALOG + * Mode 2 : | MT2063_OFFAIR_COFDM + * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS + * Mode 4 : | MT2063_OFFAIR_ANALOG + * Mode 5 : | MT2063_OFFAIR_8VSB + * --------------+---------------------------------------------- + * + * |<---------- Mode -------------->| + * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | + * ------------+-----+-----+-----+-----+-----+-----+ + * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF + * LNARin | 0 | 0 | 3 | 3 | 3 | 3 + * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 + * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 + * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 + * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 + * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 + * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 + * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 + * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 + * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 + * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 + * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 + * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 + * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 + */ + +enum mt2063_delivery_sys { + MT2063_CABLE_QAM = 0, + MT2063_CABLE_ANALOG, + MT2063_OFFAIR_COFDM, + MT2063_OFFAIR_COFDM_SAWLESS, + MT2063_OFFAIR_ANALOG, + MT2063_OFFAIR_8VSB, + MT2063_NUM_RCVR_MODES +}; + +static const char *mt2063_mode_name[] = { + [MT2063_CABLE_QAM] = "digital cable", + [MT2063_CABLE_ANALOG] = "analog cable", + [MT2063_OFFAIR_COFDM] = "digital offair", + [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", + [MT2063_OFFAIR_ANALOG] = "analog offair", + [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", +}; + +static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; +static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; +static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; +static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; +static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; +static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; +static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; +static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; +static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; + +/* + * mt2063_set_dnc_output_enable() + */ +static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, + enum MT2063_DNC_Output_Enable *pValue) +{ + dprintk(2, "\n"); + + if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ + if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ + *pValue = MT2063_DNC_NONE; + else + *pValue = MT2063_DNC_2; + } else { /* DNC1 is on */ + if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ + *pValue = MT2063_DNC_1; + else + *pValue = MT2063_DNC_BOTH; + } + return 0; +} + +/* + * mt2063_set_dnc_output_enable() + */ +static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, + enum MT2063_DNC_Output_Enable nValue) +{ + u32 status = 0; /* Status to be returned */ + u8 val = 0; + + dprintk(2, "\n"); + + /* selects, which DNC output is used */ + switch (nValue) { + case MT2063_DNC_NONE: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_1: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_2: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + case MT2063_DNC_BOTH: + val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ + if (state->reg[MT2063_REG_DNC_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_DNC_GAIN, + val); + + val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ + if (state->reg[MT2063_REG_VGA_GAIN] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_VGA_GAIN, + val); + + val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ + if (state->reg[MT2063_REG_RSVD_20] != + val) + status |= + mt2063_setreg(state, + MT2063_REG_RSVD_20, + val); + + break; + default: + break; + } + + return status; +} + +/* + * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with + * the selected enum mt2063_delivery_sys type. + * + * (DNC1GC & DNC2GC are the values, which are used, when the specific + * DNC Output is selected, the other is always off) + * + * @state: ptr to mt2063_state structure + * @Mode: desired reciever delivery system + * + * Note: Register cache must be valid for it to work + */ + +static u32 MT2063_SetReceiverMode(struct mt2063_state *state, + enum mt2063_delivery_sys Mode) +{ + u32 status = 0; /* Status to be returned */ + u8 val; + u32 longval; + + dprintk(2, "\n"); + + if (Mode >= MT2063_NUM_RCVR_MODES) + status = -ERANGE; + + /* RFAGCen */ + if (status >= 0) { + val = + (state-> + reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] + ? 0x40 : + 0x00); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + /* LNARin */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | + (LNARIN[Mode] & 0x03); + if (state->reg[MT2063_REG_CTRL_2C] != val) + status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); + } + + /* FIFFQEN and FIFFQ */ + if (status >= 0) { + val = + (state-> + reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | + (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); + if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); + /* trigger FIFF calibration, needed after changing FIFFQ */ + val = + (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); + val = + (state-> + reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); + status |= + mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); + } + } + + /* DNC1GC & DNC2GC */ + status |= mt2063_get_dnc_output_enable(state, &longval); + status |= mt2063_set_dnc_output_enable(state, longval); + + /* acLNAmax */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | + (ACLNAMAX[Mode] & 0x1F); + if (state->reg[MT2063_REG_LNA_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); + } + + /* LNATGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | + (LNATGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_LNA_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); + } + + /* ACRF */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | + (ACRFMAX[Mode] & 0x1F); + if (state->reg[MT2063_REG_RF_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); + } + + /* PD1TGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | + (PD1TGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + /* FIFATN */ + if (status >= 0) { + u8 val = ACFIFMAX[Mode]; + if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) + val = 5; + val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | + (val & 0x1F); + if (state->reg[MT2063_REG_FIF_OV] != val) + status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); + } + + /* PD2TGT */ + if (status >= 0) { + u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | + (PD2TGT[Mode] & 0x3F); + if (state->reg[MT2063_REG_PD2_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); + } + + /* Ignore ATN Overload */ + if (status >= 0) { + val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | + (RFOVDIS[Mode] ? 0x80 : 0x00); + if (state->reg[MT2063_REG_LNA_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); + } + + /* Ignore FIF Overload */ + if (status >= 0) { + val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | + (FIFOVDIS[Mode] ? 0x80 : 0x00); + if (state->reg[MT2063_REG_PD1_TGT] != val) + status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); + } + + if (status >= 0) { + state->rcvr_mode = Mode; + dprintk(1, "mt2063 mode changed to %s\n", + mt2063_mode_name[state->rcvr_mode]); + } + + return status; +} + +/* + * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various + * sections of the MT2063 + * + * @Bits: Mask bits to be cleared. + * + * See definition of MT2063_Mask_Bits type for description + * of each of the power bits. + */ +static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, + enum MT2063_Mask_Bits Bits) +{ + u32 status = 0; + + dprintk(2, "\n"); + Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ + if ((Bits & 0xFF00) != 0) { + state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); + status |= + mt2063_write(state, + MT2063_REG_PWR_2, + &state->reg[MT2063_REG_PWR_2], 1); + } + if ((Bits & 0xFF) != 0) { + state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); + status |= + mt2063_write(state, + MT2063_REG_PWR_1, + &state->reg[MT2063_REG_PWR_1], 1); + } + + return status; +} + +/* + * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. + * When Shutdown is 1, any section whose power + * mask is set will be shutdown. + */ +static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) +{ + u32 status; + + dprintk(2, "\n"); + if (Shutdown == 1) + state->reg[MT2063_REG_PWR_1] |= 0x04; + else + state->reg[MT2063_REG_PWR_1] &= ~0x04; + + status = mt2063_write(state, + MT2063_REG_PWR_1, + &state->reg[MT2063_REG_PWR_1], 1); + + if (Shutdown != 1) { + state->reg[MT2063_REG_BYP_CTRL] = + (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; + status |= + mt2063_write(state, + MT2063_REG_BYP_CTRL, + &state->reg[MT2063_REG_BYP_CTRL], + 1); + state->reg[MT2063_REG_BYP_CTRL] = + (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); + status |= + mt2063_write(state, + MT2063_REG_BYP_CTRL, + &state->reg[MT2063_REG_BYP_CTRL], + 1); + } + + return status; +} + +static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) +{ + return f_ref * (f_LO / f_ref) + + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); +} + +/** + * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. + * This function preserves maximum precision without + * risk of overflow. It accurately calculates + * f_ref * num / denom to within 1 HZ with fixed math. + * + * @num : Fractional portion of the multiplier + * @denom: denominator portion of the ratio + * @f_Ref: SRO frequency. + * + * This calculation handles f_ref as two separate 14-bit fields. + * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. + * This is the genesis of the magic number "14" and the magic mask value of + * 0x03FFF. + * + * This routine successfully handles denom values up to and including 2^18. + * Returns: f_ref * num / denom + */ +static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) +{ + u32 t1 = (f_ref >> 14) * num; + u32 term1 = t1 / denom; + u32 loss = t1 % denom; + u32 term2 = + (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; + return (term1 << 14) + term2; +} + +/* + * CalcLO1Mult()- Calculates Integer divider value and the numerator + * value for a FracN PLL. + * + * This function assumes that the f_LO and f_Ref are + * evenly divisible by f_LO_Step. + * + * @Div: OUTPUT: Whole number portion of the multiplier + * @FracN: OUTPUT: Fractional portion of the multiplier + * @f_LO: desired LO frequency. + * @f_LO_Step: Minimum step size for the LO (in Hz). + * @f_Ref: SRO frequency. + * @f_Avoid: Range of PLL frequencies to avoid near integer multiples + * of f_Ref (in Hz). + * + * Returns: Recalculated LO frequency. + */ +static u32 MT2063_CalcLO1Mult(u32 *Div, + u32 *FracN, + u32 f_LO, + u32 f_LO_Step, u32 f_Ref) +{ + /* Calculate the whole number portion of the divider */ + *Div = f_LO / f_Ref; + + /* Calculate the numerator value (round to nearest f_LO_Step) */ + *FracN = + (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + + (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); + + return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); +} + +/** + * CalcLO2Mult() - Calculates Integer divider value and the numerator + * value for a FracN PLL. + * + * This function assumes that the f_LO and f_Ref are + * evenly divisible by f_LO_Step. + * + * @Div: OUTPUT: Whole number portion of the multiplier + * @FracN: OUTPUT: Fractional portion of the multiplier + * @f_LO: desired LO frequency. + * @f_LO_Step: Minimum step size for the LO (in Hz). + * @f_Ref: SRO frequency. + * @f_Avoid: Range of PLL frequencies to avoid near + * integer multiples of f_Ref (in Hz). + * + * Returns: Recalculated LO frequency. + */ +static u32 MT2063_CalcLO2Mult(u32 *Div, + u32 *FracN, + u32 f_LO, + u32 f_LO_Step, u32 f_Ref) +{ + /* Calculate the whole number portion of the divider */ + *Div = f_LO / f_Ref; + + /* Calculate the numerator value (round to nearest f_LO_Step) */ + *FracN = + (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + + (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); + + return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, + 8191); +} + +/* + * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be + * used for a given input frequency. + * + * @state: ptr to tuner data structure + * @f_in: RF input center frequency (in Hz). + * + * Returns: ClearTune filter number (0-31) + */ +static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) +{ + u32 RFBand; + u32 idx; /* index loop */ + + /* + ** Find RF Band setting + */ + RFBand = 31; /* def when f_in > all */ + for (idx = 0; idx < 31; ++idx) { + if (state->CTFiltMax[idx] >= f_in) { + RFBand = idx; + break; + } + } + return RFBand; +} + +/* + * MT2063_Tune() - Change the tuner's tuned frequency to RFin. + */ +static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) +{ /* RF input center frequency */ + + u32 status = 0; + u32 LO1; /* 1st LO register value */ + u32 Num1; /* Numerator for LO1 reg. value */ + u32 f_IF1; /* 1st IF requested */ + u32 LO2; /* 2nd LO register value */ + u32 Num2; /* Numerator for LO2 reg. value */ + u32 ofLO1, ofLO2; /* last time's LO frequencies */ + u8 fiffc = 0x80; /* FIFF center freq from tuner */ + u32 fiffof; /* Offset from FIFF center freq */ + const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ + u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ + u8 val; + u32 RFBand; + + dprintk(2, "\n"); + /* Check the input and output frequency ranges */ + if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) + return -EINVAL; + + if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) + || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) + return -EINVAL; + + /* + * Save original LO1 and LO2 register values + */ + ofLO1 = state->AS_Data.f_LO1; + ofLO2 = state->AS_Data.f_LO2; + + /* + * Find and set RF Band setting + */ + if (state->ctfilt_sw == 1) { + val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); + if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { + status |= + mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); + } + val = state->reg[MT2063_REG_CTUNE_OV]; + RFBand = FindClearTuneFilter(state, f_in); + state->reg[MT2063_REG_CTUNE_OV] = + (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) + | RFBand); + if (state->reg[MT2063_REG_CTUNE_OV] != val) { + status |= + mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); + } + } + + /* + * Read the FIFF Center Frequency from the tuner + */ + if (status >= 0) { + status |= + mt2063_read(state, + MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + fiffc = state->reg[MT2063_REG_FIFFC]; + } + /* + * Assign in the requested values + */ + state->AS_Data.f_in = f_in; + /* Request a 1st IF such that LO1 is on a step size */ + state->AS_Data.f_if1_Request = + MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, + state->AS_Data.f_LO1_Step, + state->AS_Data.f_ref) - f_in; + + /* + * Calculate frequency settings. f_IF1_FREQ + f_in is the + * desired LO1 frequency + */ + MT2063_ResetExclZones(&state->AS_Data); + + f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); + + state->AS_Data.f_LO1 = + MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, + state->AS_Data.f_ref); + + state->AS_Data.f_LO2 = + MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + + /* + * Check for any LO spurs in the output bandwidth and adjust + * the LO settings to avoid them if needed + */ + status |= MT2063_AvoidSpurs(&state->AS_Data); + /* + * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. + * Recalculate the LO frequencies and the values to be placed + * in the tuning registers. + */ + state->AS_Data.f_LO1 = + MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, + state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); + state->AS_Data.f_LO2 = + MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + state->AS_Data.f_LO2 = + MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, + state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); + + /* + * Check the upconverter and downconverter frequency ranges + */ + if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) + || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) + status |= MT2063_UPC_RANGE; + if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) + || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) + status |= MT2063_DNC_RANGE; + /* LO2 Lock bit was in a different place for B0 version */ + if (state->tuner_id == MT2063_B0) + LO2LK = 0x40; + + /* + * If we have the same LO frequencies and we're already locked, + * then skip re-programming the LO registers. + */ + if ((ofLO1 != state->AS_Data.f_LO1) + || (ofLO2 != state->AS_Data.f_LO2) + || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != + (LO1LK | LO2LK))) { + /* + * Calculate the FIFFOF register value + * + * IF1_Actual + * FIFFOF = ------------ - 8 * FIFFC - 4992 + * f_ref/64 + */ + fiffof = + (state->AS_Data.f_LO1 - + f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - + 4992; + if (fiffof > 0xFF) + fiffof = 0xFF; + + /* + * Place all of the calculated values into the local tuner + * register fields. + */ + if (status >= 0) { + state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ + state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ + state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ + |(Num2 >> 12)); /* NUM2q (hi) */ + state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ + state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ + + /* + * Now write out the computed register values + * IMPORTANT: There is a required order for writing + * (0x05 must follow all the others). + */ + status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ + if (state->tuner_id == MT2063_B0) { + /* Re-write the one-shot bits to trigger the tune operation */ + status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ + } + /* Write out the FIFF offset only if it's changing */ + if (state->reg[MT2063_REG_FIFF_OFFSET] != + (u8) fiffof) { + state->reg[MT2063_REG_FIFF_OFFSET] = + (u8) fiffof; + status |= + mt2063_write(state, + MT2063_REG_FIFF_OFFSET, + &state-> + reg[MT2063_REG_FIFF_OFFSET], + 1); + } + } + + /* + * Check for LO's locking + */ + + if (status < 0) + return status; + + status = mt2063_lockStatus(state); + if (status < 0) + return status; + if (!status) + return -EINVAL; /* Couldn't lock */ + + /* + * If we locked OK, assign calculated data to mt2063_state structure + */ + state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; + } + + return status; +} + +static const u8 MT2063B0_defaults[] = { + /* Reg, Value */ + 0x19, 0x05, + 0x1B, 0x1D, + 0x1C, 0x1F, + 0x1D, 0x0F, + 0x1E, 0x3F, + 0x1F, 0x0F, + 0x20, 0x3F, + 0x22, 0x21, + 0x23, 0x3F, + 0x24, 0x20, + 0x25, 0x3F, + 0x27, 0xEE, + 0x2C, 0x27, /* bit at 0x20 is cleared below */ + 0x30, 0x03, + 0x2C, 0x07, /* bit at 0x20 is cleared here */ + 0x2D, 0x87, + 0x2E, 0xAA, + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ +static const u8 MT2063B1_defaults[] = { + /* Reg, Value */ + 0x05, 0xF0, + 0x11, 0x10, /* New Enable AFCsd */ + 0x19, 0x05, + 0x1A, 0x6C, + 0x1B, 0x24, + 0x1C, 0x28, + 0x1D, 0x8F, + 0x1E, 0x14, + 0x1F, 0x8F, + 0x20, 0x57, + 0x22, 0x21, /* New - ver 1.03 */ + 0x23, 0x3C, /* New - ver 1.10 */ + 0x24, 0x20, /* New - ver 1.03 */ + 0x2C, 0x24, /* bit at 0x20 is cleared below */ + 0x2D, 0x87, /* FIFFQ=0 */ + 0x2F, 0xF3, + 0x30, 0x0C, /* New - ver 1.11 */ + 0x31, 0x1B, /* New - ver 1.11 */ + 0x2C, 0x04, /* bit at 0x20 is cleared here */ + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +/* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ +static const u8 MT2063B3_defaults[] = { + /* Reg, Value */ + 0x05, 0xF0, + 0x19, 0x3D, + 0x2C, 0x24, /* bit at 0x20 is cleared below */ + 0x2C, 0x04, /* bit at 0x20 is cleared here */ + 0x28, 0xE1, /* Set the FIFCrst bit here */ + 0x28, 0xE0, /* Clear the FIFCrst bit here */ + 0x00 +}; + +static int mt2063_init(struct dvb_frontend *fe) +{ + u32 status; + struct mt2063_state *state = fe->tuner_priv; + u8 all_resets = 0xF0; /* reset/load bits */ + const u8 *def = NULL; + char *step; + u32 FCRUN; + s32 maxReads; + u32 fcu_osc; + u32 i; + + dprintk(2, "\n"); + + state->rcvr_mode = MT2063_CABLE_QAM; + + /* Read the Part/Rev code from the tuner */ + status = mt2063_read(state, MT2063_REG_PART_REV, + &state->reg[MT2063_REG_PART_REV], 1); + if (status < 0) { + printk(KERN_ERR "Can't read mt2063 part ID\n"); + return status; + } + + /* Check the part/rev code */ + switch (state->reg[MT2063_REG_PART_REV]) { + case MT2063_B0: + step = "B0"; + break; + case MT2063_B1: + step = "B1"; + break; + case MT2063_B2: + step = "B2"; + break; + case MT2063_B3: + step = "B3"; + break; + default: + printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", + state->reg[MT2063_REG_PART_REV]); + return -ENODEV; /* Wrong tuner Part/Rev code */ + } + + /* Check the 2nd byte of the Part/Rev code from the tuner */ + status = mt2063_read(state, MT2063_REG_RSVD_3B, + &state->reg[MT2063_REG_RSVD_3B], 1); + + /* b7 != 0 ==> NOT MT2063 */ + if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { + printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", + state->reg[MT2063_REG_PART_REV], + state->reg[MT2063_REG_RSVD_3B]); + return -ENODEV; /* Wrong tuner Part/Rev code */ + } + + printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); + + /* Reset the tuner */ + status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); + if (status < 0) + return status; + + /* change all of the default values that vary from the HW reset values */ + /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ + switch (state->reg[MT2063_REG_PART_REV]) { + case MT2063_B3: + def = MT2063B3_defaults; + break; + + case MT2063_B1: + def = MT2063B1_defaults; + break; + + case MT2063_B0: + def = MT2063B0_defaults; + break; + + default: + return -ENODEV; + break; + } + + while (status >= 0 && *def) { + u8 reg = *def++; + u8 val = *def++; + status = mt2063_write(state, reg, &val, 1); + } + if (status < 0) + return status; + + /* Wait for FIFF location to complete. */ + FCRUN = 1; + maxReads = 10; + while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { + msleep(2); + status = mt2063_read(state, + MT2063_REG_XO_STATUS, + &state-> + reg[MT2063_REG_XO_STATUS], 1); + FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; + } + + if (FCRUN != 0 || status < 0) + return -ENODEV; + + status = mt2063_read(state, + MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + if (status < 0) + return status; + + /* Read back all the registers from the tuner */ + status = mt2063_read(state, + MT2063_REG_PART_REV, + state->reg, MT2063_REG_END_REGS); + if (status < 0) + return status; + + /* Initialize the tuner state. */ + state->tuner_id = state->reg[MT2063_REG_PART_REV]; + state->AS_Data.f_ref = MT2063_REF_FREQ; + state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * + ((u32) state->reg[MT2063_REG_FIFFC] + 640); + state->AS_Data.f_if1_bw = MT2063_IF1_BW; + state->AS_Data.f_out = 43750000UL; + state->AS_Data.f_out_bw = 6750000UL; + state->AS_Data.f_zif_bw = MT2063_ZIF_BW; + state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; + state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; + state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; + state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; + state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; + state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; + state->AS_Data.f_LO1 = 2181000000UL; + state->AS_Data.f_LO2 = 1486249786UL; + state->f_IF1_actual = state->AS_Data.f_if1_Center; + state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; + state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; + state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; + state->num_regs = MT2063_REG_END_REGS; + state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; + state->ctfilt_sw = 0; + + state->CTFiltMax[0] = 69230000; + state->CTFiltMax[1] = 105770000; + state->CTFiltMax[2] = 140350000; + state->CTFiltMax[3] = 177110000; + state->CTFiltMax[4] = 212860000; + state->CTFiltMax[5] = 241130000; + state->CTFiltMax[6] = 274370000; + state->CTFiltMax[7] = 309820000; + state->CTFiltMax[8] = 342450000; + state->CTFiltMax[9] = 378870000; + state->CTFiltMax[10] = 416210000; + state->CTFiltMax[11] = 456500000; + state->CTFiltMax[12] = 495790000; + state->CTFiltMax[13] = 534530000; + state->CTFiltMax[14] = 572610000; + state->CTFiltMax[15] = 598970000; + state->CTFiltMax[16] = 635910000; + state->CTFiltMax[17] = 672130000; + state->CTFiltMax[18] = 714840000; + state->CTFiltMax[19] = 739660000; + state->CTFiltMax[20] = 770410000; + state->CTFiltMax[21] = 814660000; + state->CTFiltMax[22] = 846950000; + state->CTFiltMax[23] = 867820000; + state->CTFiltMax[24] = 915980000; + state->CTFiltMax[25] = 947450000; + state->CTFiltMax[26] = 983110000; + state->CTFiltMax[27] = 1021630000; + state->CTFiltMax[28] = 1061870000; + state->CTFiltMax[29] = 1098330000; + state->CTFiltMax[30] = 1138990000; + + /* + ** Fetch the FCU osc value and use it and the fRef value to + ** scale all of the Band Max values + */ + + state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; + status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, + &state->reg[MT2063_REG_CTUNE_CTRL], 1); + if (status < 0) + return status; + + /* Read the ClearTune filter calibration value */ + status = mt2063_read(state, MT2063_REG_FIFFC, + &state->reg[MT2063_REG_FIFFC], 1); + if (status < 0) + return status; + + fcu_osc = state->reg[MT2063_REG_FIFFC]; + + state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; + status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, + &state->reg[MT2063_REG_CTUNE_CTRL], 1); + if (status < 0) + return status; + + /* Adjust each of the values in the ClearTune filter cross-over table */ + for (i = 0; i < 31; i++) + state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); + + status = MT2063_SoftwareShutdown(state, 1); + if (status < 0) + return status; + status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); + if (status < 0) + return status; + + state->init = true; + + return 0; +} + +static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) +{ + struct mt2063_state *state = fe->tuner_priv; + int status; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *tuner_status = 0; + status = mt2063_lockStatus(state); + if (status < 0) + return status; + if (status) + *tuner_status = TUNER_STATUS_LOCKED; + + dprintk(1, "Tuner status: %d", *tuner_status); + + return 0; +} + +static int mt2063_release(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + fe->tuner_priv = NULL; + kfree(state); + + return 0; +} + +static int mt2063_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct mt2063_state *state = fe->tuner_priv; + s32 pict_car; + s32 pict2chanb_vsb; + s32 ch_bw; + s32 if_mid; + s32 rcvr_mode; + int status; + + dprintk(2, "\n"); + + if (!state->init) { + status = mt2063_init(fe); + if (status < 0) + return status; + } + + switch (params->mode) { + case V4L2_TUNER_RADIO: + pict_car = 38900000; + ch_bw = 8000000; + pict2chanb_vsb = -(ch_bw / 2); + rcvr_mode = MT2063_OFFAIR_ANALOG; + break; + case V4L2_TUNER_ANALOG_TV: + rcvr_mode = MT2063_CABLE_ANALOG; + if (params->std & ~V4L2_STD_MN) { + pict_car = 38900000; + ch_bw = 6000000; + pict2chanb_vsb = -1250000; + } else if (params->std & V4L2_STD_PAL_G) { + pict_car = 38900000; + ch_bw = 7000000; + pict2chanb_vsb = -1250000; + } else { /* PAL/SECAM standards */ + pict_car = 38900000; + ch_bw = 8000000; + pict2chanb_vsb = -1250000; + } + break; + default: + return -EINVAL; + } + if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); + + state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ + state->AS_Data.f_out = if_mid; + state->AS_Data.f_out_bw = ch_bw + 750000; + status = MT2063_SetReceiverMode(state, rcvr_mode); + if (status < 0) + return status; + + dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", + params->frequency, ch_bw, pict2chanb_vsb); + + status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); + if (status < 0) + return status; + + state->frequency = params->frequency; + return 0; +} + +/* + * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. + * So, the amount of the needed bandwith is given by: + * Bw = Symbol_rate * (1 + 0.15) + * As such, the maximum symbol rate supported by 6 MHz is given by: + * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds + */ +#define MAX_SYMBOL_RATE_6MHz 5217391 + +static int mt2063_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct mt2063_state *state = fe->tuner_priv; + int status; + s32 pict_car; + s32 pict2chanb_vsb; + s32 ch_bw; + s32 if_mid; + s32 rcvr_mode; + + if (!state->init) { + status = mt2063_init(fe); + if (status < 0) + return status; + } + + dprintk(2, "\n"); + + if (c->bandwidth_hz == 0) + return -EINVAL; + if (c->bandwidth_hz <= 6000000) + ch_bw = 6000000; + else if (c->bandwidth_hz <= 7000000) + ch_bw = 7000000; + else + ch_bw = 8000000; + + switch (c->delivery_system) { + case SYS_DVBT: + rcvr_mode = MT2063_OFFAIR_COFDM; + pict_car = 36125000; + pict2chanb_vsb = -(ch_bw / 2); + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + rcvr_mode = MT2063_CABLE_QAM; + pict_car = 36125000; + pict2chanb_vsb = -(ch_bw / 2); + break; + default: + return -EINVAL; + } + if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); + + state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ + state->AS_Data.f_out = if_mid; + state->AS_Data.f_out_bw = ch_bw + 750000; + status = MT2063_SetReceiverMode(state, rcvr_mode); + if (status < 0) + return status; + + dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", + c->frequency, ch_bw, pict2chanb_vsb); + + status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); + + if (status < 0) + return status; + + state->frequency = c->frequency; + return 0; +} + +static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *freq = state->AS_Data.f_out; + + dprintk(1, "IF frequency: %d\n", *freq); + + return 0; +} + +static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct mt2063_state *state = fe->tuner_priv; + + dprintk(2, "\n"); + + if (!state->init) + return -ENODEV; + + *bw = state->AS_Data.f_out_bw - 750000; + + dprintk(1, "bandwidth: %d\n", *bw); + + return 0; +} + +static struct dvb_tuner_ops mt2063_ops = { + .info = { + .name = "MT2063 Silicon Tuner", + .frequency_min = 45000000, + .frequency_max = 850000000, + .frequency_step = 0, + }, + + .init = mt2063_init, + .sleep = MT2063_Sleep, + .get_status = mt2063_get_status, + .set_analog_params = mt2063_set_analog_params, + .set_params = mt2063_set_params, + .get_if_frequency = mt2063_get_if_frequency, + .get_bandwidth = mt2063_get_bandwidth, + .release = mt2063_release, +}; + +struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c) +{ + struct mt2063_state *state = NULL; + + dprintk(2, "\n"); + + state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c = i2c; + state->frontend = fe; + state->reference = config->refclock / 1000; /* kHz */ + fe->tuner_priv = state; + fe->ops.tuner_ops = mt2063_ops; + + printk(KERN_INFO "%s: Attaching MT2063\n", __func__); + return fe; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL_GPL(mt2063_attach); + +/* + * Ancillary routines visible outside mt2063 + * FIXME: Remove them in favor of using standard tuner callbacks + */ +unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + int err = 0; + + dprintk(2, "\n"); + + err = MT2063_SoftwareShutdown(state, 1); + if (err < 0) + printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); + + return err; +} +EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); + +unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) +{ + struct mt2063_state *state = fe->tuner_priv; + int err = 0; + + dprintk(2, "\n"); + + err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); + if (err < 0) + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + + return err; +} +EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); + +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_DESCRIPTION("MT2063 Silicon tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/tuners/mt2063.h b/drivers/media/common/tuners/mt2063.h new file mode 100644 index 000000000000..62d0e8ec4e99 --- /dev/null +++ b/drivers/media/common/tuners/mt2063.h @@ -0,0 +1,36 @@ +#ifndef __MT2063_H__ +#define __MT2063_H__ + +#include "dvb_frontend.h" + +struct mt2063_config { + u8 tuner_address; + u32 refclock; +}; + +#if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE)) +struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, + struct mt2063_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +int mt2063_setTune(struct dvb_frontend *fe, u32 f_in, + u32 bw_in, + enum MTTune_atv_standard tv_type); + +/* FIXME: Should use the standard DVB attachment interfaces */ +unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); +unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); + +#endif /* CONFIG_DVB_MT2063 */ + +#endif /* __MT2063_H__ */ diff --git a/drivers/media/common/tuners/mt2131.c b/drivers/media/common/tuners/mt2131.c index a4f830bb25d1..f83b0c1ea6c8 100644 --- a/drivers/media/common/tuners/mt2131.c +++ b/drivers/media/common/tuners/mt2131.c @@ -92,9 +92,9 @@ static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) return 0; } -static int mt2131_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mt2131_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2131_priv *priv; int ret=0, i; u32 freq; @@ -105,12 +105,8 @@ static int mt2131_set_params(struct dvb_frontend *fe, u8 lockval = 0; priv = fe->tuner_priv; - if (fe->ops.info.type == FE_OFDM) - priv->bandwidth = params->u.ofdm.bandwidth; - else - priv->bandwidth = 0; - freq = params->frequency / 1000; // Hz -> kHz + freq = c->frequency / 1000; /* Hz -> kHz */ dprintk(1, "%s() freq=%d\n", __func__, freq); f_lo1 = freq + MT2131_IF1 * 1000; @@ -193,14 +189,6 @@ static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct mt2131_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __func__); - *bandwidth = priv->bandwidth; - return 0; -} - static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) { struct mt2131_priv *priv = fe->tuner_priv; @@ -263,7 +251,6 @@ static const struct dvb_tuner_ops mt2131_tuner_ops = { .set_params = mt2131_set_params, .get_frequency = mt2131_get_frequency, - .get_bandwidth = mt2131_get_bandwidth, .get_status = mt2131_get_status }; @@ -281,7 +268,6 @@ struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, return NULL; priv->cfg = cfg; - priv->bandwidth = 6000000; /* 6MHz */ priv->i2c = i2c; if (mt2131_readreg(priv, 0, &id) != 0) { diff --git a/drivers/media/common/tuners/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h index 4e05a67e88c1..62aeedf5c550 100644 --- a/drivers/media/common/tuners/mt2131_priv.h +++ b/drivers/media/common/tuners/mt2131_priv.h @@ -38,7 +38,6 @@ struct mt2131_priv { struct i2c_adapter *i2c; u32 frequency; - u32 bandwidth; }; #endif /* __MT2131_PRIV_H__ */ diff --git a/drivers/media/common/tuners/mt2266.c b/drivers/media/common/tuners/mt2266.c index 25a8ea342c46..bca4d75e42d4 100644 --- a/drivers/media/common/tuners/mt2266.c +++ b/drivers/media/common/tuners/mt2266.c @@ -122,8 +122,9 @@ static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, #define FREF 30000 // Quartz oscillator 30 MHz -static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int mt2266_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct mt2266_priv *priv; int ret=0; u32 freq; @@ -135,32 +136,32 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame priv = fe->tuner_priv; - freq = params->frequency / 1000; // Hz -> kHz + freq = priv->frequency / 1000; /* Hz -> kHz */ if (freq < 470000 && freq > 230000) return -EINVAL; /* Gap between VHF and UHF bands */ - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - priv->frequency = freq * 1000; + priv->frequency = c->frequency; tune = 2 * freq * (8192/16) / (FREF/16); band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; if (band == MT2266_VHF) tune *= 2; - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: mt2266_writeregs(priv, mt2266_init_6mhz, sizeof(mt2266_init_6mhz)); break; - case BANDWIDTH_7_MHZ: - mt2266_writeregs(priv, mt2266_init_7mhz, - sizeof(mt2266_init_7mhz)); - break; - case BANDWIDTH_8_MHZ: - default: + case 8000000: mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); break; + case 7000000: + default: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; } + priv->bandwidth = c->bandwidth_hz; if (band == MT2266_VHF && priv->band == MT2266_UHF) { dprintk("Switch from UHF to VHF"); diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c index 54be9e6faaaf..6133315fb0e3 100644 --- a/drivers/media/common/tuners/mxl5005s.c +++ b/drivers/media/common/tuners/mxl5005s.c @@ -3979,54 +3979,47 @@ static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, return 0; } -static int mxl5005s_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mxl5005s_set_params(struct dvb_frontend *fe) { struct mxl5005s_state *state = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; u32 req_mode, req_bw = 0; int ret; dprintk(1, "%s()\n", __func__); - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - req_mode = MXL_ATSC; break; - default: - case QAM_64: - case QAM_256: - case QAM_AUTO: - req_mode = MXL_QAM; break; - } - } else + switch (delsys) { + case SYS_ATSC: + req_mode = MXL_ATSC; + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case SYS_DVBC_ANNEX_B: + req_mode = MXL_QAM; + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + default: /* Assume DVB-T */ req_mode = MXL_DVBT; - - /* Change tuner for new modulation type if reqd */ - if (req_mode != state->current_mode) { - switch (req_mode) { - case MXL_ATSC: - case MXL_QAM: - req_bw = MXL5005S_BANDWIDTH_6MHZ; + switch (bw) { + case 6000000: + req_bw = MXL5005S_BANDWIDTH_6MHZ; + break; + case 7000000: + req_bw = MXL5005S_BANDWIDTH_7MHZ; + break; + case 8000000: + case 0: + req_bw = MXL5005S_BANDWIDTH_8MHZ; break; - case MXL_DVBT: default: - /* Assume DVB-T */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - req_bw = MXL5005S_BANDWIDTH_6MHZ; - break; - case BANDWIDTH_7_MHZ: - req_bw = MXL5005S_BANDWIDTH_7MHZ; - break; - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: - req_bw = MXL5005S_BANDWIDTH_8MHZ; - break; - default: - return -EINVAL; - } + return -EINVAL; } + } + /* Change tuner for new modulation type if reqd */ + if (req_mode != state->current_mode || + req_bw != state->Chan_Bandwidth) { state->current_mode = req_mode; ret = mxl5005s_reconfigure(fe, req_mode, req_bw); @@ -4034,8 +4027,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe, ret = 0; if (ret == 0) { - dprintk(1, "%s() freq=%d\n", __func__, params->frequency); - ret = mxl5005s_SetRfFreqHz(fe, params->frequency); + dprintk(1, "%s() freq=%d\n", __func__, c->frequency); + ret = mxl5005s_SetRfFreqHz(fe, c->frequency); } return ret; diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index 5d02221e99dd..69e453ef0a1a 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -165,6 +165,8 @@ struct mxl5007t_state { struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; + enum mxl5007t_if_freq if_freq; + u32 frequency; u32 bandwidth; }; @@ -286,6 +288,8 @@ static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, /* set inverted IF or normal IF */ set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); + state->if_freq = if_freq; + return; } @@ -612,47 +616,43 @@ fail: /* ------------------------------------------------------------------------- */ -static int mxl5007t_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mxl5007t_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; struct mxl5007t_state *state = fe->tuner_priv; enum mxl5007t_bw_mhz bw; enum mxl5007t_mode mode; int ret; - u32 freq = params->frequency; + u32 freq = c->frequency; - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - mode = MxL_MODE_ATSC; - break; - case QAM_64: - case QAM_256: - mode = MxL_MODE_CABLE; - break; - default: - mxl_err("modulation not set!"); - return -EINVAL; - } + switch (delsys) { + case SYS_ATSC: + mode = MxL_MODE_ATSC; + bw = MxL_BW_6MHz; + break; + case SYS_DVBC_ANNEX_B: + mode = MxL_MODE_CABLE; bw = MxL_BW_6MHz; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + break; + case SYS_DVBT: + case SYS_DVBT2: + mode = MxL_MODE_DVBT; + switch (c->bandwidth_hz) { + case 6000000: bw = MxL_BW_6MHz; break; - case BANDWIDTH_7_MHZ: + case 7000000: bw = MxL_BW_7MHz; break; - case BANDWIDTH_8_MHZ: + case 8000000: bw = MxL_BW_8MHz; break; default: - mxl_err("bandwidth not set!"); return -EINVAL; } - mode = MxL_MODE_DVBT; - } else { + break; + default: mxl_err("modulation type not supported!"); return -EINVAL; } @@ -671,8 +671,7 @@ static int mxl5007t_set_params(struct dvb_frontend *fe, goto fail; state->frequency = freq; - state->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + state->bandwidth = c->bandwidth_hz; fail: mutex_unlock(&state->lock); @@ -738,6 +737,50 @@ static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MxL_IF_4_MHZ: + *frequency = 4000000; + break; + case MxL_IF_4_5_MHZ: + *frequency = 4500000; + break; + case MxL_IF_4_57_MHZ: + *frequency = 4570000; + break; + case MxL_IF_5_MHZ: + *frequency = 5000000; + break; + case MxL_IF_5_38_MHZ: + *frequency = 5380000; + break; + case MxL_IF_6_MHZ: + *frequency = 6000000; + break; + case MxL_IF_6_28_MHZ: + *frequency = 6280000; + break; + case MxL_IF_9_1915_MHZ: + *frequency = 9191500; + break; + case MxL_IF_35_25_MHZ: + *frequency = 35250000; + break; + case MxL_IF_36_15_MHZ: + *frequency = 36150000; + break; + case MxL_IF_44_MHZ: + *frequency = 44000000; + break; + } + return 0; +} + static int mxl5007t_release(struct dvb_frontend *fe) { struct mxl5007t_state *state = fe->tuner_priv; @@ -767,6 +810,7 @@ static struct dvb_tuner_ops mxl5007t_tuner_ops = { .get_frequency = mxl5007t_get_frequency, .get_bandwidth = mxl5007t_get_bandwidth, .release = mxl5007t_release, + .get_if_frequency = mxl5007t_get_if_frequency, }; static int mxl5007t_get_chip_id(struct mxl5007t_state *state) diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c index 9f5dba244cb8..2d79b1f5d5eb 100644 --- a/drivers/media/common/tuners/qt1010.c +++ b/drivers/media/common/tuners/qt1010.c @@ -82,9 +82,9 @@ static void qt1010_dump_regs(struct qt1010_priv *priv) printk(KERN_CONT "\n"); } -static int qt1010_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int qt1010_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct qt1010_priv *priv; int err; u32 freq, div, mod1, mod2; @@ -144,13 +144,11 @@ static int qt1010_set_params(struct dvb_frontend *fe, #define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ priv = fe->tuner_priv; - freq = params->frequency; + freq = c->frequency; div = (freq + QT1010_OFFSET) / QT1010_STEP; freq = (div * QT1010_STEP) - QT1010_OFFSET; mod1 = (freq + QT1010_OFFSET) % FREQ1; mod2 = (freq + QT1010_OFFSET) % FREQ2; - priv->bandwidth = - (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; priv->frequency = freq; if (fe->ops.i2c_gate_ctrl) @@ -320,7 +318,7 @@ static u8 qt1010_init_meas2(struct qt1010_priv *priv, static int qt1010_init(struct dvb_frontend *fe) { struct qt1010_priv *priv = fe->tuner_priv; - struct dvb_frontend_parameters params; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int err = 0; u8 i, tmpval, *valptr = NULL; @@ -397,9 +395,9 @@ static int qt1010_init(struct dvb_frontend *fe) if ((err = qt1010_init_meas2(priv, i, &tmpval))) return err; - params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */ + c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */ /* MSI Megasky 580 GL861 533000000 */ - return qt1010_set_params(fe, ¶ms); + return qt1010_set_params(fe); } static int qt1010_release(struct dvb_frontend *fe) @@ -416,10 +414,9 @@ static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - struct qt1010_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; + *frequency = 36125000; return 0; } @@ -437,7 +434,7 @@ static const struct dvb_tuner_ops qt1010_tuner_ops = { .set_params = qt1010_set_params, .get_frequency = qt1010_get_frequency, - .get_bandwidth = qt1010_get_bandwidth + .get_if_frequency = qt1010_get_if_frequency, }; struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h index 090cf475f099..2c42d3f01636 100644 --- a/drivers/media/common/tuners/qt1010_priv.h +++ b/drivers/media/common/tuners/qt1010_priv.h @@ -99,7 +99,6 @@ struct qt1010_priv { u8 reg25_init_val; u32 frequency; - u32 bandwidth; }; #endif diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c index e29cc2bc113a..602c2e392b17 100644 --- a/drivers/media/common/tuners/tda18212.c +++ b/drivers/media/common/tuners/tda18212.c @@ -25,6 +25,8 @@ struct tda18212_priv { struct tda18212_config *cfg; struct i2c_adapter *i2c; + + u32 if_frequency; }; #define dbg(fmt, arg...) \ @@ -128,20 +130,31 @@ static void tda18212_dump_regs(struct tda18212_priv *priv) } #endif -static int tda18212_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda18212_set_params(struct dvb_frontend *fe) { struct tda18212_priv *priv = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_khz; u8 buf[9]; + #define DVBT_6 0 + #define DVBT_7 1 + #define DVBT_8 2 + #define DVBT2_6 3 + #define DVBT2_7 4 + #define DVBT2_8 5 + #define DVBC_6 6 + #define DVBC_8 7 static const u8 bw_params[][3] = { - /* 0f 13 23 */ - { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */ - { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */ - { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */ - { 0x92, 0x53, 0x03 }, /* DVB-C */ + /* reg: 0f 13 23 */ + [DVBT_6] = { 0xb3, 0x20, 0x03 }, + [DVBT_7] = { 0xb3, 0x31, 0x01 }, + [DVBT_8] = { 0xb3, 0x22, 0x01 }, + [DVBT2_6] = { 0xbc, 0x20, 0x03 }, + [DVBT2_7] = { 0xbc, 0x72, 0x03 }, + [DVBT2_8] = { 0xbc, 0x22, 0x01 }, + [DVBC_6] = { 0x92, 0x50, 0x03 }, + [DVBC_8] = { 0x92, 0x53, 0x03 }, }; dbg("delsys=%d RF=%d BW=%d\n", @@ -155,24 +168,44 @@ static int tda18212_set_params(struct dvb_frontend *fe, switch (c->bandwidth_hz) { case 6000000: if_khz = priv->cfg->if_dvbt_6; - i = 0; + i = DVBT_6; break; case 7000000: if_khz = priv->cfg->if_dvbt_7; - i = 1; + i = DVBT_7; break; case 8000000: if_khz = priv->cfg->if_dvbt_8; - i = 2; + i = DVBT_8; break; default: ret = -EINVAL; goto error; } break; - case SYS_DVBC_ANNEX_AC: + case SYS_DVBT2: + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg->if_dvbt2_6; + i = DVBT2_6; + break; + case 7000000: + if_khz = priv->cfg->if_dvbt2_7; + i = DVBT2_7; + break; + case 8000000: + if_khz = priv->cfg->if_dvbt2_8; + i = DVBT2_8; + break; + default: + ret = -EINVAL; + goto error; + } + break; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: if_khz = priv->cfg->if_dvbc; - i = 3; + i = DVBC_8; break; default: ret = -EINVAL; @@ -194,7 +227,7 @@ static int tda18212_set_params(struct dvb_frontend *fe, buf[0] = 0x02; buf[1] = bw_params[i][1]; buf[2] = 0x03; /* default value */ - buf[3] = if_khz / 50; + buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); buf[4] = ((c->frequency / 1000) >> 16) & 0xff; buf[5] = ((c->frequency / 1000) >> 8) & 0xff; buf[6] = ((c->frequency / 1000) >> 0) & 0xff; @@ -204,6 +237,9 @@ static int tda18212_set_params(struct dvb_frontend *fe, if (ret) goto error; + /* actual IF rounded as it is on register */ + priv->if_frequency = buf[3] * 50 * 1000; + exit: if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ @@ -215,6 +251,15 @@ error: goto exit; } +static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18212_priv *priv = fe->tuner_priv; + + *frequency = priv->if_frequency; + + return 0; +} + static int tda18212_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -234,6 +279,7 @@ static const struct dvb_tuner_ops tda18212_tuner_ops = { .release = tda18212_release, .set_params = tda18212_set_params, + .get_if_frequency = tda18212_get_if_frequency, }; struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h index 83b497f59e1b..9bd5da4aabb7 100644 --- a/drivers/media/common/tuners/tda18212.h +++ b/drivers/media/common/tuners/tda18212.h @@ -29,6 +29,10 @@ struct tda18212_config { u16 if_dvbt_6; u16 if_dvbt_7; u16 if_dvbt_8; + u16 if_dvbt2_5; + u16 if_dvbt2_6; + u16 if_dvbt2_7; + u16 if_dvbt2_8; u16 if_dvbc; }; diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c index 4fc29730a12c..dfb3a831df45 100644 --- a/drivers/media/common/tuners/tda18218.c +++ b/drivers/media/common/tuners/tda18218.c @@ -109,10 +109,11 @@ static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) return tda18218_rd_regs(priv, reg, val, 1); } -static int tda18218_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda18218_set_params(struct dvb_frontend *fe) { struct tda18218_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 bw = c->bandwidth_hz; int ret; u8 buf[3], i, BP_Filter, LP_Fc; u32 LO_Frac; @@ -138,22 +139,19 @@ static int tda18218_set_params(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ /* low-pass filter cut-off frequency */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + if (bw <= 6000000) { LP_Fc = 0; - LO_Frac = params->frequency + 3000000; - break; - case BANDWIDTH_7_MHZ: + priv->if_frequency = 3000000; + } else if (bw <= 7000000) { LP_Fc = 1; - LO_Frac = params->frequency + 3500000; - break; - case BANDWIDTH_8_MHZ: - default: + priv->if_frequency = 3500000; + } else { LP_Fc = 2; - LO_Frac = params->frequency + 4000000; - break; + priv->if_frequency = 4000000; } + LO_Frac = c->frequency + priv->if_frequency; + /* band-pass filter */ if (LO_Frac < 188000000) BP_Filter = 3; @@ -206,6 +204,14 @@ error: return ret; } +static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18218_priv *priv = fe->tuner_priv; + *frequency = priv->if_frequency; + dbg("%s: if=%d", __func__, *frequency); + return 0; +} + static int tda18218_sleep(struct dvb_frontend *fe) { struct tda18218_priv *priv = fe->tuner_priv; @@ -268,6 +274,8 @@ static const struct dvb_tuner_ops tda18218_tuner_ops = { .sleep = tda18218_sleep, .set_params = tda18218_set_params, + + .get_if_frequency = tda18218_get_if_frequency, }; struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h index 904e5365c78c..dc52b72e1407 100644 --- a/drivers/media/common/tuners/tda18218_priv.h +++ b/drivers/media/common/tuners/tda18218_priv.h @@ -100,6 +100,8 @@ struct tda18218_priv { struct tda18218_config *cfg; struct i2c_adapter *i2c; + u32 if_frequency; + u8 regs[TDA18218_NUM_REGS]; }; diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 63cc4004e211..2e67f4459904 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -928,59 +928,49 @@ fail: /* ------------------------------------------------------------------ */ -static int tda18271_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda18271_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 freq = c->frequency; struct tda18271_priv *priv = fe->tuner_priv; struct tda18271_std_map *std_map = &priv->std; struct tda18271_std_map_item *map; int ret; - u32 bw, freq = params->frequency; priv->mode = TDA18271_DIGITAL; - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - map = &std_map->atsc_6; - break; - case QAM_64: - case QAM_256: - map = &std_map->qam_6; - break; - default: - tda_warn("modulation not set!\n"); - return -EINVAL; - } -#if 0 - /* userspace request is already center adjusted */ - freq += 1750000; /* Adjust to center (+1.75MHZ) */ -#endif + switch (delsys) { + case SYS_ATSC: + map = &std_map->atsc_6; bw = 6000000; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6000000; + break; + case SYS_ISDBT: + case SYS_DVBT: + case SYS_DVBT2: + if (bw <= 6000000) { map = &std_map->dvbt_6; - break; - case BANDWIDTH_7_MHZ: - bw = 7000000; + } else if (bw <= 7000000) { map = &std_map->dvbt_7; - break; - case BANDWIDTH_8_MHZ: - bw = 8000000; + } else { map = &std_map->dvbt_8; - break; - default: - tda_warn("bandwidth not set!\n"); - return -EINVAL; } - } else if (fe->ops.info.type == FE_QAM) { - /* DVB-C */ - map = &std_map->qam_8; - bw = 8000000; - } else { + break; + case SYS_DVBC_ANNEX_B: + bw = 6000000; + /* falltrough */ + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (bw <= 6000000) { + map = &std_map->qam_6; + } else if (bw <= 7000000) { + map = &std_map->qam_7; + } else { + map = &std_map->qam_8; + } + break; + default: tda_warn("modulation type not supported!\n"); return -EINVAL; } @@ -994,9 +984,9 @@ static int tda18271_set_params(struct dvb_frontend *fe, if (tda_fail(ret)) goto fail; + priv->if_freq = map->if_freq; priv->frequency = freq; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + priv->bandwidth = bw; fail: return ret; } @@ -1050,6 +1040,7 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe, if (tda_fail(ret)) goto fail; + priv->if_freq = map->if_freq; priv->frequency = freq; priv->bandwidth = 0; fail: @@ -1086,6 +1077,13 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = (u32)priv->if_freq * 1000; + return 0; +} + /* ------------------------------------------------------------------ */ #define tda18271_update_std(std_cfg, name) do { \ @@ -1245,6 +1243,7 @@ static const struct dvb_tuner_ops tda18271_tuner_ops = { .set_config = tda18271_set_config, .get_frequency = tda18271_get_frequency, .get_bandwidth = tda18271_get_bandwidth, + .get_if_frequency = tda18271_get_if_frequency, }; struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index 3d5b6ab7e332..fb881c667c94 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -1213,6 +1213,8 @@ static struct tda18271_std_map tda18271c1_std_map = { .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ }; @@ -1244,6 +1246,8 @@ static struct tda18271_std_map tda18271c2_std_map = { .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ + .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, + .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ }; diff --git a/drivers/media/common/tuners/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 94340f47562b..454c152ccaa0 100644 --- a/drivers/media/common/tuners/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h @@ -122,6 +122,8 @@ struct tda18271_priv { struct mutex lock; + u16 if_freq; + u32 frequency; u32 bandwidth; }; diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h index 50cfa8cebb93..640bae4e6a5a 100644 --- a/drivers/media/common/tuners/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h @@ -53,6 +53,7 @@ struct tda18271_std_map { struct tda18271_std_map_item dvbt_7; struct tda18271_std_map_item dvbt_8; struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_7; struct tda18271_std_map_item qam_8; }; diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c index e0d5b43772b8..a0d176267470 100644 --- a/drivers/media/common/tuners/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c @@ -152,9 +152,9 @@ static int tuner_transfer(struct dvb_frontend *fe, return rc; } -static int tda827xo_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda827xo_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tda827x_priv *priv = fe->tuner_priv; u8 buf[14]; int rc; @@ -165,18 +165,16 @@ static int tda827xo_set_params(struct dvb_frontend *fe, u32 N; dprintk("%s:\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + if (c->bandwidth_hz == 0) { + if_freq = 5000000; + } else if (c->bandwidth_hz <= 6000000) { if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: + } else if (c->bandwidth_hz <= 7000000) { if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ + } else { /* 8 MHz */ if_freq = 5000000; - break; } - tuner_freq = params->frequency; + tuner_freq = c->frequency; i = 0; while (tda827x_table[i].lomax < tuner_freq) { @@ -220,8 +218,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe, if (rc < 0) goto err; - priv->frequency = params->frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->frequency = c->frequency; + priv->bandwidth = c->bandwidth_hz; return 0; @@ -513,9 +511,9 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, } } -static int tda827xa_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda827xa_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tda827x_priv *priv = fe->tuner_priv; struct tda827xa_data *frequency_map = tda827xa_dvbt; u8 buf[11]; @@ -531,22 +529,25 @@ static int tda827xa_set_params(struct dvb_frontend *fe, tda827xa_lna_gain(fe, 1, NULL); msleep(20); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + if (c->bandwidth_hz == 0) { + if_freq = 5000000; + } else if (c->bandwidth_hz <= 6000000) { if_freq = 4000000; - break; - case BANDWIDTH_7_MHZ: + } else if (c->bandwidth_hz <= 7000000) { if_freq = 4500000; - break; - default: /* 8 MHz or Auto */ + } else { /* 8 MHz */ if_freq = 5000000; - break; } - tuner_freq = params->frequency; + tuner_freq = c->frequency; - if (fe->ops.info.type == FE_QAM) { + switch (c->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: dprintk("%s select tda827xa_dvbc\n", __func__); frequency_map = tda827xa_dvbc; + break; + default: + break; } i = 0; @@ -645,9 +646,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe, if (rc < 0) goto err; - priv->frequency = params->frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; - + priv->frequency = c->frequency; + priv->bandwidth = c->bandwidth_hz; return 0; diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index f8ee29e6059c..39e7e583c8c0 100644 --- a/drivers/media/common/tuners/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c @@ -751,6 +751,17 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, if (4 != rc) tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + /* Write AUX byte */ + switch (priv->type) { + case TUNER_PHILIPS_FM1216ME_MK3: + buffer[2] = 0x98; + buffer[3] = 0x20; /* set TOP AGC */ + rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); + if (4 != rc) + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); + break; + } + return 0; } @@ -780,24 +791,26 @@ static int simple_set_params(struct dvb_frontend *fe, } static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) + const u32 delsys, + const u32 frequency, + const u32 bandwidth) { struct tuner_simple_priv *priv = fe->tuner_priv; switch (priv->type) { case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_PHILIPS_FMD1216MEX_MK3: - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ && - params->frequency >= 158870000) + if (bandwidth == 8000000 && + frequency >= 158870000) buf[3] |= 0x08; break; case TUNER_PHILIPS_TD1316: /* determine band */ - buf[3] |= (params->frequency < 161000000) ? 1 : - (params->frequency < 444000000) ? 2 : 4; + buf[3] |= (frequency < 161000000) ? 1 : + (frequency < 444000000) ? 2 : 4; /* setup PLL filter */ - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + if (bandwidth == 8000000) buf[3] |= 1 << 3; break; case TUNER_PHILIPS_TUV1236D: @@ -808,12 +821,11 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, if (dtv_input[priv->nr]) new_rf = dtv_input[priv->nr]; else - switch (params->u.vsb.modulation) { - case QAM_64: - case QAM_256: + switch (delsys) { + case SYS_DVBC_ANNEX_B: new_rf = 1; break; - case VSB_8: + case SYS_ATSC: default: new_rf = 0; break; @@ -827,7 +839,9 @@ static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, } static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) + const u32 delsys, + const u32 freq, + const u32 bw) { /* This function returns the tuned frequency on success, 0 on error */ struct tuner_simple_priv *priv = fe->tuner_priv; @@ -836,7 +850,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, u8 config, cb; u32 div; int ret; - unsigned frequency = params->frequency / 62500; + u32 frequency = freq / 62500; if (!tun->stepsize) { /* tuner-core was loaded before the digital tuner was @@ -860,7 +874,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, buf[2] = config; buf[3] = cb; - simple_set_dvb(fe, buf, params); + simple_set_dvb(fe, buf, delsys, freq, bw); tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", tun->name, div, buf[0], buf[1], buf[2], buf[3]); @@ -870,32 +884,37 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, } static int simple_dvb_calc_regs(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, u8 *buf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; struct tuner_simple_priv *priv = fe->tuner_priv; u32 frequency; if (buf_len < 5) return -EINVAL; - frequency = simple_dvb_configure(fe, buf+1, params); + frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw); if (frequency == 0) return -EINVAL; buf[0] = priv->i2c_props.addr; priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + priv->bandwidth = c->bandwidth_hz; return 5; } -static int simple_dvb_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int simple_dvb_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; + u32 freq = c->frequency; struct tuner_simple_priv *priv = fe->tuner_priv; + u32 frequency; u32 prev_freq, prev_bw; int ret; u8 buf[5]; @@ -906,9 +925,14 @@ static int simple_dvb_set_params(struct dvb_frontend *fe, prev_freq = priv->frequency; prev_bw = priv->bandwidth; - ret = simple_dvb_calc_regs(fe, params, buf, 5); - if (ret != 5) - goto fail; + frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw); + if (frequency == 0) + return -EINVAL; + + buf[0] = priv->i2c_props.addr; + + priv->frequency = frequency; + priv->bandwidth = bw; /* put analog demod in standby when tuning digital */ if (fe->ops.analog_ops.standby) diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 3acbaa04e1b3..27555995f7e4 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -311,7 +311,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) n_array, fname, name, priv->firm_version >> 8, priv->firm_version & 0xff); - priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); if (priv->firm == NULL) { tuner_err("Not enough memory to load firmware file.\n"); rc = -ENOMEM; @@ -891,7 +891,7 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) /* Frequency is locked */ if (frq_lock == 1) - signal = 32768; + signal = 1 << 11; /* Get SNR of the video signal */ rc = xc2028_get_reg(priv, 0x0040, &signal); @@ -962,14 +962,24 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * For DTV 7/8, the firmware uses BW = 8000, so it needs a * further adjustment to get the frequency center on VHF */ + + /* + * The firmware DTV78 used to work fine in UHF band (8 MHz + * bandwidth) but not at all in VHF band (7 MHz bandwidth). + * The real problem was connected to the formula used to + * calculate the center frequency offset in VHF band. + * In fact, removing the 500KHz adjustment fixed the problem. + * This is coherent to what was implemented for the DTV7 + * firmware. + * In the end, now the center frequency is the same for all 3 + * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel + * bandwidth. + */ + if (priv->cur_fw.type & DTV6) offset = 1750000; - else if (priv->cur_fw.type & DTV7) - offset = 2250000; - else /* DTV8 or DTV78 */ + else /* DTV7 or DTV8 or DTV78 */ offset = 2750000; - if ((priv->cur_fw.type & DTV78) && freq < 470000000) - offset -= 500000; /* * xc3028 additional "magic" @@ -979,17 +989,13 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * newer firmwares */ -#if 1 /* * The proper adjustment would be to do it at s-code table. * However, this didn't work, as reported by * Robert Lowery <rglowery@exemail.com.au> */ - if (priv->cur_fw.type & DTV7) - offset += 500000; - -#else +#if 0 /* * Still need tests for XC3028L (firmware 3.2 or upper) * So, for now, let's just comment the per-firmware @@ -1084,68 +1090,28 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, V4L2_TUNER_ANALOG_TV, type, p->std, 0); } -static int xc2028_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int xc2028_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; struct xc2028_data *priv = fe->tuner_priv; unsigned int type=0; - fe_bandwidth_t bw = BANDWIDTH_8_MHZ; u16 demod = 0; tuner_dbg("%s called\n", __func__); - switch(fe->ops.info.type) { - case FE_OFDM: - bw = p->u.ofdm.bandwidth; + switch (delsys) { + case SYS_DVBT: + case SYS_DVBT2: /* * The only countries with 6MHz seem to be Taiwan/Uruguay. * Both seem to require QAM firmware for OFDM decoding * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com> */ - if (bw == BANDWIDTH_6_MHZ) + if (bw <= 6000000) type |= QAM; - break; - case FE_ATSC: - bw = BANDWIDTH_6_MHZ; - /* The only ATSC firmware (at least on v2.7) is D2633 */ - type |= ATSC | D2633; - break; - /* DVB-S and pure QAM (FE_QAM) are not supported */ - default: - return -EINVAL; - } - - switch (bw) { - case BANDWIDTH_8_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 0; - else - priv->ctrl.uhfbw8 = 1; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; - type |= F8MHZ; - break; - case BANDWIDTH_7_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 1; - else - priv->ctrl.uhfbw8 = 0; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; - type |= F8MHZ; - break; - case BANDWIDTH_6_MHZ: - type |= DTV6; - priv->ctrl.vhfbw7 = 0; - priv->ctrl.uhfbw8 = 0; - break; - default: - tuner_err("error: bandwidth not supported.\n"); - }; - /* - Selects between D2633 or D2620 firmware. - It doesn't make sense for ATSC, since it should be D2633 on all cases - */ - if (fe->ops.info.type != FE_ATSC) { switch (priv->ctrl.type) { case XC2028_D2633: type |= D2633; @@ -1161,6 +1127,34 @@ static int xc2028_set_params(struct dvb_frontend *fe, else type |= D2620; } + break; + case SYS_ATSC: + /* The only ATSC firmware (at least on v2.7) is D2633 */ + type |= ATSC | D2633; + break; + /* DVB-S and pure QAM (FE_QAM) are not supported */ + default: + return -EINVAL; + } + + if (bw <= 6000000) { + type |= DTV6; + priv->ctrl.vhfbw7 = 0; + priv->ctrl.uhfbw8 = 0; + } else if (bw <= 7000000) { + if (c->frequency < 470000000) + priv->ctrl.vhfbw7 = 1; + else + priv->ctrl.uhfbw8 = 0; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; + type |= F8MHZ; + } else { + if (c->frequency < 470000000) + priv->ctrl.vhfbw7 = 0; + else + priv->ctrl.uhfbw8 = 1; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; + type |= F8MHZ; } /* All S-code tables need a 200kHz shift */ @@ -1185,7 +1179,7 @@ static int xc2028_set_params(struct dvb_frontend *fe, */ } - return generic_set_freq(fe, p->frequency, + return generic_set_freq(fe, c->frequency, V4L2_TUNER_DIGITAL_TV, type, 0, demod); } diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 634f4d9b6c63..d218c1d68c33 100644 --- a/drivers/media/common/tuners/xc4000.c +++ b/drivers/media/common/tuners/xc4000.c @@ -758,7 +758,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe) n_array, fname, name, priv->firm_version >> 8, priv->firm_version & 0xff); - priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); if (priv->firm == NULL) { printk(KERN_ERR "Not enough memory to load firmware file.\n"); rc = -ENOMEM; @@ -1121,83 +1121,62 @@ static void xc_debug_dump(struct xc4000_priv *priv) dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); } -static int xc4000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int xc4000_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + u32 bw = c->bandwidth_hz; struct xc4000_priv *priv = fe->tuner_priv; unsigned int type; int ret = -EREMOTEIO; - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); mutex_lock(&priv->lock); - if (fe->ops.info.type == FE_ATSC) { - dprintk(1, "%s() ATSC\n", __func__); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = XC4000_DTV6; - type = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = XC4000_DTV6; - type = DTV6; - break; - default: - ret = -EINVAL; - goto fail; - } - } else if (fe->ops.info.type == FE_OFDM) { + switch (delsys) { + case SYS_ATSC: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = c->frequency - 1750000; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case SYS_DVBC_ANNEX_B: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = c->frequency - 1750000; + priv->video_standard = XC4000_DTV6; + type = DTV6; + break; + case SYS_DVBT: + case SYS_DVBT2: dprintk(1, "%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - priv->bandwidth = BANDWIDTH_6_MHZ; + if (bw == 0) { + if (c->frequency < 400000000) { + priv->freq_hz = c->frequency - 2250000; + } else { + priv->freq_hz = c->frequency - 2750000; + } + priv->video_standard = XC4000_DTV7_8; + type = DTV78; + } else if (bw <= 6000000) { priv->video_standard = XC4000_DTV6; - priv->freq_hz = params->frequency - 1750000; + priv->freq_hz = c->frequency - 1750000; type = DTV6; - break; - case BANDWIDTH_7_MHZ: - priv->bandwidth = BANDWIDTH_7_MHZ; + } else if (bw <= 7000000) { priv->video_standard = XC4000_DTV7; - priv->freq_hz = params->frequency - 2250000; + priv->freq_hz = c->frequency - 2250000; type = DTV7; - break; - case BANDWIDTH_8_MHZ: - priv->bandwidth = BANDWIDTH_8_MHZ; + } else { priv->video_standard = XC4000_DTV8; - priv->freq_hz = params->frequency - 2750000; + priv->freq_hz = c->frequency - 2750000; type = DTV8; - break; - case BANDWIDTH_AUTO: - if (params->frequency < 400000000) { - priv->bandwidth = BANDWIDTH_7_MHZ; - priv->freq_hz = params->frequency - 2250000; - } else { - priv->bandwidth = BANDWIDTH_8_MHZ; - priv->freq_hz = params->frequency - 2750000; - } - priv->video_standard = XC4000_DTV7_8; - type = DTV78; - break; - default: - printk(KERN_ERR "xc4000 bandwidth not set!\n"); - ret = -EINVAL; - goto fail; } priv->rf_mode = XC_RF_MODE_AIR; - } else { - printk(KERN_ERR "xc4000 modulation type not supported!\n"); + break; + default: + printk(KERN_ERR "xc4000 delivery system not supported!\n"); ret = -EINVAL; goto fail; } @@ -1209,6 +1188,8 @@ static int xc4000_set_params(struct dvb_frontend *fe, if (check_firmware(fe, type, 0, priv->if_khz) != 0) goto fail; + priv->bandwidth = c->bandwidth_hz; + ret = xc_set_signal_source(priv, priv->rf_mode); if (ret != 0) { printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", @@ -1605,7 +1586,7 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, break; case 1: /* new tuner instance */ - priv->bandwidth = BANDWIDTH_6_MHZ; + priv->bandwidth = 6000000; /* set default configuration */ priv->if_khz = 4560; priv->default_pm = 0; diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index aa1b2e844d32..296df05b8cda 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -628,20 +628,13 @@ static void xc_debug_dump(struct xc5000_priv *priv) dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); } -/* - * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. - * So, the amount of the needed bandwith is given by: - * Bw = Symbol_rate * (1 + 0.15) - * As such, the maximum symbol rate supported by 6 MHz is given by: - * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds - */ -#define MAX_SYMBOL_RATE_6MHz 5217391 - -static int xc5000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int xc5000_set_params(struct dvb_frontend *fe) { + int ret, b; struct xc5000_priv *priv = fe->tuner_priv; - int ret; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + u32 freq = fe->dtv_property_cache.frequency; + u32 delsys = fe->dtv_property_cache.delivery_system; if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { @@ -650,88 +643,69 @@ static int xc5000_set_params(struct dvb_frontend *fe, } } - dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency); - - if (fe->ops.info.type == FE_ATSC) { - dprintk(1, "%s() ATSC\n", __func__); - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - default: - return -EINVAL; - } - } else if (fe->ops.info.type == FE_OFDM) { + dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); + + switch (delsys) { + case SYS_ATSC: + dprintk(1, "%s() VSB modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = freq - 1750000; + priv->video_standard = DTV6; + break; + case SYS_DVBC_ANNEX_B: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = freq - 1750000; + priv->video_standard = DTV6; + break; + case SYS_DVBT: + case SYS_DVBT2: dprintk(1, "%s() OFDM\n", __func__); - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - priv->bandwidth = BANDWIDTH_6_MHZ; + switch (bw) { + case 6000000: priv->video_standard = DTV6; - priv->freq_hz = params->frequency - 1750000; + priv->freq_hz = freq - 1750000; break; - case BANDWIDTH_7_MHZ: - printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n"); - return -EINVAL; - case BANDWIDTH_8_MHZ: - priv->bandwidth = BANDWIDTH_8_MHZ; + case 7000000: + priv->video_standard = DTV7; + priv->freq_hz = freq - 2250000; + break; + case 8000000: priv->video_standard = DTV8; - priv->freq_hz = params->frequency - 2750000; + priv->freq_hz = freq - 2750000; break; default: printk(KERN_ERR "xc5000 bandwidth not set!\n"); return -EINVAL; } priv->rf_mode = XC_RF_MODE_AIR; - } else if (fe->ops.info.type == FE_QAM) { - switch (params->u.qam.modulation) { - case QAM_256: - case QAM_AUTO: - case QAM_16: - case QAM_32: - case QAM_64: - case QAM_128: - dprintk(1, "%s() QAM modulation\n", __func__); - priv->rf_mode = XC_RF_MODE_CABLE; - /* - * Using a 8MHz bandwidth sometimes fail - * with 6MHz-spaced channels, due to inter-carrier - * interference. So, use DTV6 firmware - */ - if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) { - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - priv->freq_hz = params->frequency - 1750000; - } else { - priv->bandwidth = BANDWIDTH_8_MHZ; - priv->video_standard = DTV7_8; - priv->freq_hz = params->frequency - 2750000; - } - break; - default: - dprintk(1, "%s() Unsupported QAM type\n", __func__); - return -EINVAL; + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->rf_mode = XC_RF_MODE_CABLE; + if (bw <= 6000000) { + priv->video_standard = DTV6; + priv->freq_hz = freq - 1750000; + b = 6; + } else if (bw <= 7000000) { + priv->video_standard = DTV7; + priv->freq_hz = freq - 2250000; + b = 7; + } else { + priv->video_standard = DTV7_8; + priv->freq_hz = freq - 2750000; + b = 8; } - } else { - printk(KERN_ERR "xc5000 modulation type not supported!\n"); + dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, + b, bw); + break; + default: + printk(KERN_ERR "xc5000: delivery system is not supported!\n"); return -EINVAL; } - dprintk(1, "%s() frequency=%d (compensated)\n", - __func__, priv->freq_hz); + dprintk(1, "%s() frequency=%d (compensated to %d)\n", + __func__, freq, priv->freq_hz); ret = xc_SetSignalSource(priv, priv->rf_mode); if (ret != XC_RESULT_SUCCESS) { @@ -763,6 +737,8 @@ static int xc5000_set_params(struct dvb_frontend *fe, if (debug) xc_debug_dump(priv); + priv->bandwidth = bw; + return 0; } @@ -968,6 +944,14 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) return 0; } +static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __func__); + *freq = priv->if_khz * 1000; + return 0; +} + static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1108,6 +1092,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .set_params = xc5000_set_params, .set_analog_params = xc5000_set_analog_params, .get_frequency = xc5000_get_frequency, + .get_if_frequency = xc5000_get_if_frequency, .get_bandwidth = xc5000_get_bandwidth, .get_status = xc5000_get_status }; @@ -1135,7 +1120,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, break; case 1: /* new tuner instance */ - priv->bandwidth = BANDWIDTH_6_MHZ; + priv->bandwidth = 6000000; fe->tuner_priv = priv; break; default: diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 2df1b0214dcd..b1e8c99f469b 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -86,7 +86,8 @@ static int flexcop_dvb_init(struct flexcop_device *fc) fc->demux.stop_feed = flexcop_dvb_stop_feed; fc->demux.write_to_decoder = NULL; - if ((ret = dvb_dmx_init(&fc->demux)) < 0) { + ret = dvb_dmx_init(&fc->demux); + if (ret < 0) { err("dvb_dmx failed: error %d", ret); goto err_dmx; } @@ -96,32 +97,42 @@ static int flexcop_dvb_init(struct flexcop_device *fc) fc->dmxdev.filternum = fc->demux.feednum; fc->dmxdev.demux = &fc->demux.dmx; fc->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter)) < 0) { + ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter); + if (ret < 0) { err("dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } - if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend); + if (ret < 0) { err("adding hw_frontend to dmx failed: error %d", ret); goto err_dmx_add_hw_frontend; } fc->mem_frontend.source = DMX_MEMORY_FE; - if ((ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend)) < 0) { + ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend); + if (ret < 0) { err("adding mem_frontend to dmx failed: error %d", ret); goto err_dmx_add_mem_frontend; } - if ((ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend)) < 0) { + ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend); + if (ret < 0) { err("connect frontend failed: error %d", ret); goto err_connect_frontend; } - dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); + if (ret < 0) { + err("dvb_net_init failed: error %d", ret); + goto err_net; + } fc->init_state |= FC_STATE_DVB_INIT; return 0; +err_net: + fc->demux.dmx.disconnect_frontend(&fc->demux.dmx); err_connect_frontend: fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend); err_dmx_add_mem_frontend: @@ -254,7 +265,8 @@ int flexcop_device_initialize(struct flexcop_device *fc) flexcop_hw_filter_init(fc); flexcop_smc_ctrl(fc, 0); - if ((ret = flexcop_dvb_init(fc))) + ret = flexcop_dvb_init(fc); + if (ret) goto error; /* i2c has to be done before doing EEProm stuff - @@ -272,7 +284,8 @@ int flexcop_device_initialize(struct flexcop_device *fc) } else warn("reading of MAC address failed.\n"); - if ((ret = flexcop_frontend_init(fc))) + ret = flexcop_frontend_init(fc); + if (ret) goto error; flexcop_device_name(fc,"initialization of","complete"); diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index caa4e18ed1c1..430b3eb11815 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -386,7 +386,7 @@ static int dst_set_freq(struct dst_state *state, u32 freq) return 0; } -static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) +static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) { state->bandwidth = bandwidth; @@ -394,7 +394,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) return -EOPNOTSUPP; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: if (state->dst_hw_cap & DST_TYPE_HAS_CA) state->tx_tuna[7] = 0x06; else { @@ -402,7 +402,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) state->tx_tuna[7] = 0x00; } break; - case BANDWIDTH_7_MHZ: + case 7000000: if (state->dst_hw_cap & DST_TYPE_HAS_CA) state->tx_tuna[7] = 0x07; else { @@ -410,7 +410,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth) state->tx_tuna[7] = 0x00; } break; - case BANDWIDTH_8_MHZ: + case 8000000: if (state->dst_hw_cap & DST_TYPE_HAS_CA) state->tx_tuna[7] = 0x08; else { @@ -1561,7 +1561,7 @@ static int dst_init(struct dvb_frontend *fe) state->tone = SEC_TONE_OFF; state->diseq_flags = 0; state->k22 = 0x02; - state->bandwidth = BANDWIDTH_7_MHZ; + state->bandwidth = 7000000; state->cur_jiff = jiffies; if (state->dst_type == DST_TYPE_IS_SAT) memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); @@ -1609,8 +1609,9 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) return retval; } -static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dst_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int retval = -EINVAL; struct dst_state *state = fe->demodulator_priv; @@ -1623,17 +1624,17 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); + dst_set_bandwidth(state, p->bandwidth_hz); else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_modulation(state, p->modulation); } retval = dst_write_tuna(fe); } @@ -1642,31 +1643,32 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet } static int dst_tune_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* p, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { struct dst_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; - if (p != NULL) { + if (re_tune) { dst_set_freq(state, p->frequency); dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) dst_set_inversion(state, p->inversion); - dst_set_fec(state, p->u.qpsk.fec_inner); - dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) - dst_set_bandwidth(state, p->u.ofdm.bandwidth); + dst_set_bandwidth(state, p->bandwidth_hz); else if (state->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(state, p->u.qam.fec_inner); - dst_set_symbolrate(state, p->u.qam.symbol_rate); - dst_set_modulation(state, p->u.qam.modulation); + dst_set_fec(state, p->fec_inner); + dst_set_symbolrate(state, p->symbol_rate); + dst_set_modulation(state, p->modulation); } dst_write_tuna(fe); } @@ -1683,22 +1685,23 @@ static int dst_get_tuning_algo(struct dvb_frontend *fe) return dst_algo ? DVBFE_ALGO_HW : DVBFE_ALGO_SW; } -static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dst_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dst_state *state = fe->demodulator_priv; p->frequency = state->decode_freq; if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) p->inversion = state->inversion; - p->u.qpsk.symbol_rate = state->symbol_rate; - p->u.qpsk.fec_inner = dst_get_fec(state); + p->symbol_rate = state->symbol_rate; + p->fec_inner = dst_get_fec(state); } else if (state->dst_type == DST_TYPE_IS_TERR) { - p->u.ofdm.bandwidth = state->bandwidth; + p->bandwidth_hz = state->bandwidth; } else if (state->dst_type == DST_TYPE_IS_CABLE) { - p->u.qam.symbol_rate = state->symbol_rate; - p->u.qam.fec_inner = dst_get_fec(state); - p->u.qam.modulation = dst_get_modulation(state); + p->symbol_rate = state->symbol_rate; + p->fec_inner = dst_get_fec(state); + p->modulation = dst_get_modulation(state); } return 0; @@ -1756,10 +1759,9 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad EXPORT_SYMBOL(dst_attach); static struct dvb_frontend_ops dst_dvbt_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "DST DVB-T", - .type = FE_OFDM, .frequency_min = 137000000, .frequency_max = 858000000, .frequency_stepsize = 166667, @@ -1786,10 +1788,9 @@ static struct dvb_frontend_ops dst_dvbt_ops = { }; static struct dvb_frontend_ops dst_dvbs_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "DST DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, /* kHz for QPSK frontends */ @@ -1816,10 +1817,9 @@ static struct dvb_frontend_ops dst_dvbs_ops = { }; static struct dvb_frontend_ops dst_dvbc_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "DST DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 51000000, .frequency_max = 858000000, @@ -1846,9 +1846,9 @@ static struct dvb_frontend_ops dst_dvbc_ops = { }; static struct dvb_frontend_ops dst_atsc_ops = { + .delsys = { SYS_ATSC }, .info = { .name = "DST ATSC", - .type = FE_ATSC, .frequency_stepsize = 62500, .frequency_min = 510000000, .frequency_max = 858000000, diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index d88cf2add82b..d70d98f1a571 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -124,7 +124,7 @@ struct dst_state { u16 decode_snr; unsigned long cur_jiff; u8 k22; - fe_bandwidth_t bandwidth; + u32 bandwidth; u32 dst_hw_cap; u8 dst_fw_version; fe_sec_mini_cmd_t minicmd; diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 521d69104982..81fab9adc1ca 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -19,6 +19,8 @@ * */ +#define pr_fmt(fmt) "dvb_bt8xx: " fmt + #include <linux/bitops.h> #include <linux/module.h> #include <linux/init.h> @@ -148,8 +150,9 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) return 0; } -static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 div; unsigned char bs = 0; unsigned char cp = 0; @@ -157,18 +160,18 @@ static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_f if (buf_len < 5) return -EINVAL; - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 542000000) + if (c->frequency < 542000000) cp = 0xb4; - else if (params->frequency < 771000000) + else if (c->frequency < 771000000) cp = 0xbc; else cp = 0xf4; - if (params->frequency == 0) + if (c->frequency == 0) bs = 0x03; - else if (params->frequency < 443250000) + else if (c->frequency < 443250000) bs = 0x02; else bs = 0x08; @@ -191,13 +194,12 @@ static struct zl10353_config thomson_dtt7579_zl10353_config = { .demod_address = 0x0f, }; -static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int cx24108_tuner_set_params(struct dvb_frontend *fe) { - u32 freq = params->frequency; - + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 freq = c->frequency; int i, a, n, pump; u32 band, pll; - u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, 1576000,1718000,1856000,2036000,2150000}; u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, @@ -205,7 +207,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend 0x00120000,0x00140000}; #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ - printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); + dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq); /* This is really the bit driving the tuner chip cx24108 */ @@ -216,7 +218,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend /* decide which VCO to use for the input frequency */ for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); - printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq); + dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq); band=bandsel[i]; /* the gain values must be set by SetSymbolrate */ /* compute the pll divider needed, from Conexant data sheet, @@ -232,7 +234,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend ((a&0x1f)<<11); /* everything is shifted left 11 bits to left-align the bits in the 32bit word. Output to the tuner goes MSB-aligned, after all */ - printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a); + dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a); cx24110_pll_write(fe,band); /* set vga and vca to their widest-band settings, as a precaution. SetSymbolrate might not be called to set this up */ @@ -267,31 +269,32 @@ static struct cx24110_config pctvsat_config = { .demod_address = 0x55, }; -static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; u8 cfg, cpump, band_select; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (36000000 + params->frequency + 83333) / 166666; + div = (36000000 + c->frequency + 83333) / 166666; cfg = 0x88; - if (params->frequency < 175000000) + if (c->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) + else if (c->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) + else if (c->frequency < 750000000) cpump = 2; else cpump = 3; - if (params->frequency < 175000000) + if (c->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) band_select = 0x05; else band_select = 0x03; @@ -342,50 +345,51 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) return 0; } -static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 div; unsigned char bs = 0; unsigned char cp = 0; if (buf_len < 5) return -EINVAL; - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - if (params->frequency < 150000000) + if (c->frequency < 150000000) cp = 0xB4; - else if (params->frequency < 173000000) + else if (c->frequency < 173000000) cp = 0xBC; - else if (params->frequency < 250000000) + else if (c->frequency < 250000000) cp = 0xB4; - else if (params->frequency < 400000000) + else if (c->frequency < 400000000) cp = 0xBC; - else if (params->frequency < 420000000) + else if (c->frequency < 420000000) cp = 0xF4; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) cp = 0xFC; - else if (params->frequency < 600000000) + else if (c->frequency < 600000000) cp = 0xBC; - else if (params->frequency < 730000000) + else if (c->frequency < 730000000) cp = 0xF4; else cp = 0xFC; - if (params->frequency < 150000000) + if (c->frequency < 150000000) bs = 0x01; - else if (params->frequency < 173000000) + else if (c->frequency < 173000000) bs = 0x01; - else if (params->frequency < 250000000) + else if (c->frequency < 250000000) bs = 0x02; - else if (params->frequency < 400000000) + else if (c->frequency < 400000000) bs = 0x02; - else if (params->frequency < 420000000) + else if (c->frequency < 420000000) bs = 0x02; - else if (params->frequency < 470000000) + else if (c->frequency < 470000000) bs = 0x02; - else if (params->frequency < 600000000) + else if (c->frequency < 600000000) bs = 0x08; - else if (params->frequency < 730000000) + else if (c->frequency < 730000000) bs = 0x08; else bs = 0x08; @@ -461,25 +465,26 @@ static struct or51211_config or51211_config = { .sleep = or51211_sleep, }; -static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; - div = (params->frequency + 36166667) / 166667; + div = (c->frequency + 36166667) / 166667; buf[0] = (div >> 8) & 0x7F; buf[1] = div & 0xFF; buf[2] = 0x85; - if ((params->frequency >= 47000000) && (params->frequency < 153000000)) + if ((c->frequency >= 47000000) && (c->frequency < 153000000)) buf[3] = 0x01; - else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) + else if ((c->frequency >= 153000000) && (c->frequency < 430000000)) buf[3] = 0x02; - else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) + else if ((c->frequency >= 430000000) && (c->frequency < 824000000)) buf[3] = 0x0C; - else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) + else if ((c->frequency >= 824000000) && (c->frequency < 863000000)) buf[3] = 0x8C; else return -EINVAL; @@ -513,31 +518,31 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) return 0; } -static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) +static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len) { u32 div; - struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; if (buf_len < 5) return -EINVAL; - div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; pllbuf[0] = 0x61; pllbuf[1] = (div >> 8) & 0x7F; pllbuf[2] = div & 0xFF; pllbuf[3] = 0x85; - dprintk("frequency %u, div %u\n", params->frequency, div); + dprintk("frequency %u, div %u\n", c->frequency, div); - if (params->frequency < 470000000) + if (c->frequency < 470000000) pllbuf[4] = 0x02; - else if (params->frequency > 823000000) + else if (c->frequency > 823000000) pllbuf[4] = 0x88; else pllbuf[4] = 0x08; - if (op->bandwidth == 8) + if (c->bandwidth_hz == 8000000) pllbuf[4] |= 0x04; return 5; @@ -663,7 +668,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) /* DST is not a frontend driver !!! */ state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); if (!state) { - printk("dvb_bt8xx: No memory\n"); + pr_err("No memory\n"); break; } /* Setup the Card */ @@ -673,7 +678,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) state->dst_ca = NULL; /* DST is not a frontend, attaching the ASIC */ if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { - printk("%s: Could not find a Twinhan DST.\n", __func__); + pr_err("%s: Could not find a Twinhan DST\n", __func__); break; } /* Attach other DST peripherals if any */ @@ -702,14 +707,14 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } if (card->fe == NULL) - printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", card->bt->dev->vendor, card->bt->dev->device, card->bt->dev->subsystem_vendor, card->bt->dev->subsystem_device); else if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { - printk("dvb-bt8xx: Frontend registration failed!\n"); + pr_err("Frontend registration failed!\n"); dvb_frontend_detach(card->fe); card->fe = NULL; } @@ -723,7 +728,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) THIS_MODULE, &card->bt->dev->dev, adapter_nr); if (result < 0) { - printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); + pr_err("dvb_register_adapter failed (errno = %d)\n", result); return result; } card->dvb_adapter.priv = card; @@ -741,66 +746,69 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) card->demux.stop_feed = dvb_bt8xx_stop_feed; card->demux.write_to_decoder = NULL; - if ((result = dvb_dmx_init(&card->demux)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = dvb_dmx_init(&card->demux); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_unregister_adaptor; } card->dmxdev.filternum = 256; card->dmxdev.demux = &card->demux.dmx; card->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) { - printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result); - - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter); + if (result < 0) { + pr_err("dvb_dmxdev_init failed (errno = %d)\n", result); + goto err_dmx_release; } card->fe_hw.source = DMX_FRONTEND_0; - if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_dmxdev_release; } card->fe_mem.source = DMX_MEMORY_FE; - if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_remove_hw_frontend; } - if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { - printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); - - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); - card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); - dvb_dmxdev_release(&card->dmxdev); - dvb_dmx_release(&card->demux); - dvb_unregister_adapter(&card->dvb_adapter); - return result; + result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw); + if (result < 0) { + pr_err("dvb_dmx_init failed (errno = %d)\n", result); + goto err_remove_mem_frontend; } - dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); + if (result < 0) { + pr_err("dvb_net_init failed (errno = %d)\n", result); + goto err_disconnect_frontend; + } tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); frontend_init(card, type); return 0; + +err_disconnect_frontend: + card->demux.dmx.disconnect_frontend(&card->demux.dmx); +err_remove_mem_frontend: + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); +err_remove_hw_frontend: + card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); +err_dmxdev_release: + dvb_dmxdev_release(&card->dmxdev); +err_dmx_release: + dvb_dmx_release(&card->demux); +err_unregister_adaptor: + dvb_unregister_adapter(&card->dvb_adapter); + return result; } static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) @@ -881,8 +889,7 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) break; default: - printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", - sub->core->type); + pr_err("Unknown bttv card type: %d\n", sub->core->type); kfree(card); return -ENODEV; } @@ -890,16 +897,14 @@ static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { - printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr); + pr_err("no pci device for card %d\n", card->bttv_nr); kfree(card); return -ENODEV; } if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { - printk("dvb_bt8xx: unable to determine DMA core of card %d,\n", - card->bttv_nr); - printk("dvb_bt8xx: if you have the ALSA bt87x audio driver " - "installed, try removing it.\n"); + pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr); + pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n"); kfree(card); return -ENODEV; diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c index d1e91bc80e78..ce4f85849e7b 100644 --- a/drivers/media/dvb/ddbridge/ddbridge-core.c +++ b/drivers/media/dvb/ddbridge/ddbridge-core.c @@ -580,7 +580,7 @@ static int demod_attach_drxk(struct ddb_input *input) memset(&config, 0, sizeof(config)); config.adr = 0x29 + (input->nr & 1); - fe = input->fe = dvb_attach(drxk_attach, &config, i2c, &input->fe2); + fe = input->fe = dvb_attach(drxk_attach, &config, i2c); if (!input->fe) { printk(KERN_ERR "No DRXK found!\n"); return -ENODEV; diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 55e6533f15e9..a609b3a9b146 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -1115,11 +1115,14 @@ static int __devinit dm1105_probe(struct pci_dev *pdev, if (ret < 0) goto err_remove_mem_frontend; - ret = frontend_init(dev); + ret = dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); if (ret < 0) goto err_disconnect_frontend; - dvb_net_init(dvb_adapter, &dev->dvbnet, dmx); + ret = frontend_init(dev); + if (ret < 0) + goto err_dvb_net; + dm1105_ir_init(dev); INIT_WORK(&dev->work, dm1105_dmx_buffer); diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 7ea517b7e186..9be65a3b931f 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1306,6 +1306,10 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, /* fragment the packets & store in the buffer */ while (fragpos < count) { fraglen = ca->slot_info[slot].link_buf_size - 2; + if (fraglen < 0) + break; + if (fraglen > HOST_LINK_BUF_SIZE - 2) + fraglen = HOST_LINK_BUF_SIZE - 2; if ((count - fragpos) < fraglen) fraglen = count - fragpos; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2c0acdb4d811..b15db4fe347b 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -25,6 +25,9 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ +/* Enables DVBv3 compatibility bits at the headers */ +#define __DVB_CORE__ + #include <linux/string.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -105,7 +108,6 @@ struct dvb_frontend_private { /* thread/frontend values */ struct dvb_device *dvbdev; - struct dvb_frontend_parameters parameters_in; struct dvb_frontend_parameters parameters_out; struct dvb_fe_events events; struct semaphore sem; @@ -139,6 +141,62 @@ struct dvb_frontend_private { }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); +static int dtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out); + +static bool has_get_frontend(struct dvb_frontend *fe) +{ + return fe->ops.get_frontend; +} + +/* + * Due to DVBv3 API calls, a delivery system should be mapped into one of + * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC), + * otherwise, a DVBv3 call will fail. + */ +enum dvbv3_emulation_type { + DVBV3_UNKNOWN, + DVBV3_QPSK, + DVBV3_QAM, + DVBV3_OFDM, + DVBV3_ATSC, +}; + +static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system) +{ + switch (delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + return DVBV3_QAM; + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + case SYS_DSS: + return DVBV3_QPSK; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DMBTH: + return DVBV3_OFDM; + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + return DVBV3_ATSC; + case SYS_UNDEFINED: + case SYS_ISDBC: + case SYS_DVBH: + case SYS_DAB: + case SYS_ATSCMH: + default: + /* + * Doesn't know how to emulate those types and/or + * there's no frontend driver from this type yet + * with some emulation code, so, we're not sure yet how + * to handle them, or they're not compatible with a DVBv3 call. + */ + return DVBV3_UNKNOWN; + } +} static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { @@ -149,8 +207,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) dprintk ("%s\n", __func__); - if ((status & FE_HAS_LOCK) && fe->ops.get_frontend) - fe->ops.get_frontend(fe, &fepriv->parameters_out); + if ((status & FE_HAS_LOCK) && has_get_frontend(fe)) + dtv_get_frontend(fe, &fepriv->parameters_out); mutex_lock(&events->mtx); @@ -277,12 +335,13 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra int ready = 0; int fe_set_err = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int original_inversion = fepriv->parameters_in.inversion; - u32 original_frequency = fepriv->parameters_in.frequency; + struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; + int original_inversion = c->inversion; + u32 original_frequency = c->frequency; /* are we using autoinversion? */ autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters_in.inversion == INVERSION_AUTO)); + (c->inversion == INVERSION_AUTO)); /* setup parameters correctly */ while(!ready) { @@ -348,19 +407,20 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); /* set the frontend itself */ - fepriv->parameters_in.frequency += fepriv->lnb_drift; + c->frequency += fepriv->lnb_drift; if (autoinversion) - fepriv->parameters_in.inversion = fepriv->inversion; + c->inversion = fepriv->inversion; + tmp = *c; if (fe->ops.set_frontend) - fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in); - fepriv->parameters_out = fepriv->parameters_in; + fe_set_err = fe->ops.set_frontend(fe); + *c = tmp; if (fe_set_err < 0) { fepriv->state = FESTATE_ERROR; return fe_set_err; } - fepriv->parameters_in.frequency = original_frequency; - fepriv->parameters_in.inversion = original_inversion; + c->frequency = original_frequency; + c->inversion = original_inversion; fepriv->auto_sub_step++; return 0; @@ -371,6 +431,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) fe_status_t s = 0; int retval = 0; struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; /* if we've got no parameters, just keep idling */ if (fepriv->state & FESTATE_IDLE) { @@ -382,10 +443,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* in SCAN mode, we just set the frontend when asked and leave it alone */ if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { if (fepriv->state & FESTATE_RETUNE) { + tmp = *c; if (fe->ops.set_frontend) - retval = fe->ops.set_frontend(fe, - &fepriv->parameters_in); - fepriv->parameters_out = fepriv->parameters_in; + retval = fe->ops.set_frontend(fe); + *c = tmp; if (retval < 0) fepriv->state = FESTATE_ERROR; else @@ -415,8 +476,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* if we're tuned, then we have determined the correct inversion */ if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters_in.inversion == INVERSION_AUTO)) { - fepriv->parameters_in.inversion = fepriv->inversion; + (c->inversion == INVERSION_AUTO)) { + c->inversion = fepriv->inversion; } return; } @@ -507,7 +568,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe) return 1; if (fepriv->dvbdev->writers == 1) - if (time_after(jiffies, fepriv->release_jiffies + + if (time_after_eq(jiffies, fepriv->release_jiffies + dvb_shutdown_timeout * HZ)) return 1; @@ -540,7 +601,7 @@ static int dvb_frontend_thread(void *data) fe_status_t s; enum dvbfe_algo algo; - struct dvb_frontend_parameters *params; + bool re_tune = false; dprintk("%s\n", __func__); @@ -589,18 +650,15 @@ restart: switch (algo) { case DVBFE_ALGO_HW: dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); - params = NULL; /* have we been asked to RETUNE ? */ if (fepriv->state & FESTATE_RETUNE) { dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); - params = &fepriv->parameters_in; + re_tune = true; fepriv->state = FESTATE_TUNED; } if (fe->ops.tune) - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); - if (params) - fepriv->parameters_out = *params; + fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s); if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { dprintk("%s: state changed, adding current state\n", __func__); @@ -624,7 +682,7 @@ restart: */ if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { if (fe->ops.search) { - fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in); + fepriv->algo_status = fe->ops.search(fe); /* We did do a search as was requested, the flags are * now unset as well and has the flags wrt to search. */ @@ -633,14 +691,10 @@ restart: } } /* Track the carrier if the search was successful */ - if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { - if (fe->ops.track) - fe->ops.track(fe, &fepriv->parameters_in); - } else { + if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) { fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; fepriv->delay = HZ / 2; } - fepriv->parameters_out = fepriv->parameters_in; fe->ops.read_status(fe, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); /* update event list */ @@ -807,52 +861,40 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, fe->dvb->num,fe->id); } -static int dvb_frontend_check_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *parms) +static int dvb_frontend_check_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 freq_min; u32 freq_max; /* range check: frequency */ dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); - if ((freq_min && parms->frequency < freq_min) || - (freq_max && parms->frequency > freq_max)) { + if ((freq_min && c->frequency < freq_min) || + (freq_max && c->frequency > freq_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max); + fe->dvb->num, fe->id, c->frequency, freq_min, freq_max); return -EINVAL; } /* range check: symbol rate */ - if (fe->ops.info.type == FE_QPSK) { - if ((fe->ops.info.symbol_rate_min && - parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || - (fe->ops.info.symbol_rate_max && - parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { - printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate, - fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); - return -EINVAL; - } - - } else if (fe->ops.info.type == FE_QAM) { + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: if ((fe->ops.info.symbol_rate_min && - parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || + c->symbol_rate < fe->ops.info.symbol_rate_min) || (fe->ops.info.symbol_rate_max && - parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { + c->symbol_rate > fe->ops.info.symbol_rate_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, parms->u.qam.symbol_rate, - fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); + fe->dvb->num, fe->id, c->symbol_rate, + fe->ops.info.symbol_rate_min, + fe->ops.info.symbol_rate_max); return -EINVAL; } - } - - /* check for supported modulation */ - if (fe->ops.info.type == FE_QAM && - (parms->u.qam.modulation > QAM_AUTO || - !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { - printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", - fe->dvb->num, fe->id, parms->u.qam.modulation); - return -EINVAL; + default: + break; } return 0; @@ -866,28 +908,52 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) memset(c, 0, sizeof(struct dtv_frontend_properties)); c->state = DTV_CLEAR; - c->delivery_system = SYS_UNDEFINED; - c->inversion = INVERSION_AUTO; - c->fec_inner = FEC_AUTO; + + dprintk("%s() Clearing cache for delivery system %d\n", __func__, + c->delivery_system); + c->transmission_mode = TRANSMISSION_MODE_AUTO; - c->bandwidth_hz = BANDWIDTH_AUTO; + c->bandwidth_hz = 0; /* AUTO */ c->guard_interval = GUARD_INTERVAL_AUTO; c->hierarchy = HIERARCHY_AUTO; - c->symbol_rate = QAM_AUTO; + c->symbol_rate = 0; c->code_rate_HP = FEC_AUTO; c->code_rate_LP = FEC_AUTO; - - c->isdbt_partial_reception = -1; - c->isdbt_sb_mode = -1; - c->isdbt_sb_subchannel = -1; - c->isdbt_sb_segment_idx = -1; - c->isdbt_sb_segment_count = -1; - c->isdbt_layer_enabled = 0x7; + c->fec_inner = FEC_AUTO; + c->rolloff = ROLLOFF_AUTO; + c->voltage = SEC_VOLTAGE_OFF; + c->sectone = SEC_TONE_OFF; + c->pilot = PILOT_AUTO; + + c->isdbt_partial_reception = 0; + c->isdbt_sb_mode = 0; + c->isdbt_sb_subchannel = 0; + c->isdbt_sb_segment_idx = 0; + c->isdbt_sb_segment_count = 0; + c->isdbt_layer_enabled = 0; for (i = 0; i < 3; i++) { c->layer[i].fec = FEC_AUTO; c->layer[i].modulation = QAM_AUTO; - c->layer[i].interleaving = -1; - c->layer[i].segment_count = -1; + c->layer[i].interleaving = 0; + c->layer[i].segment_count = 0; + } + + c->isdbs_ts_id = 0; + c->dvbt2_plp_id = 0; + + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + c->modulation = QPSK; /* implied for DVB-S in legacy API */ + c->rolloff = ROLLOFF_35;/* implied for DVB-S */ + break; + case SYS_ATSC: + c->modulation = VSB_8; + break; + default: + c->modulation = QAM_AUTO; + break; } return 0; @@ -973,6 +1039,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), _DTV_CMD(DTV_HIERARCHY, 0, 0), + + _DTV_CMD(DTV_ENUM_DELSYS, 0, 0), }; static void dtv_property_dump(struct dtv_property *tvp) @@ -1006,70 +1074,54 @@ static void dtv_property_dump(struct dtv_property *tvp) dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); } -static int is_legacy_delivery_system(fe_delivery_system_t s) -{ - if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || - (s == SYS_ATSC)) - return 1; - - return 0; -} - -/* Initialize the cache with some default values derived from the - * legacy frontend_info structure. - */ -static void dtv_property_cache_init(struct dvb_frontend *fe, - struct dtv_frontend_properties *c) -{ - switch (fe->ops.info.type) { - case FE_QPSK: - c->modulation = QPSK; /* implied for DVB-S in legacy API */ - c->rolloff = ROLLOFF_35;/* implied for DVB-S */ - c->delivery_system = SYS_DVBS; - break; - case FE_QAM: - c->delivery_system = SYS_DVBC_ANNEX_AC; - break; - case FE_OFDM: - c->delivery_system = SYS_DVBT; - break; - case FE_ATSC: - break; - } -} - /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. */ -static void dtv_property_cache_sync(struct dvb_frontend *fe, - struct dtv_frontend_properties *c, - const struct dvb_frontend_parameters *p) +static int dtv_property_cache_sync(struct dvb_frontend *fe, + struct dtv_frontend_properties *c, + const struct dvb_frontend_parameters *p) { c->frequency = p->frequency; c->inversion = p->inversion; - switch (fe->ops.info.type) { - case FE_QPSK: + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_QPSK: + dprintk("%s() Preparing QPSK req\n", __func__); c->symbol_rate = p->u.qpsk.symbol_rate; c->fec_inner = p->u.qpsk.fec_inner; break; - case FE_QAM: + case DVBV3_QAM: + dprintk("%s() Preparing QAM req\n", __func__); c->symbol_rate = p->u.qam.symbol_rate; c->fec_inner = p->u.qam.fec_inner; c->modulation = p->u.qam.modulation; break; - case FE_OFDM: - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - c->bandwidth_hz = 6000000; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - c->bandwidth_hz = 7000000; - else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + case DVBV3_OFDM: + dprintk("%s() Preparing OFDM req\n", __func__); + switch (p->u.ofdm.bandwidth) { + case BANDWIDTH_10_MHZ: + c->bandwidth_hz = 10000000; + break; + case BANDWIDTH_8_MHZ: c->bandwidth_hz = 8000000; - else - /* Including BANDWIDTH_AUTO */ + break; + case BANDWIDTH_7_MHZ: + c->bandwidth_hz = 7000000; + break; + case BANDWIDTH_6_MHZ: + c->bandwidth_hz = 6000000; + break; + case BANDWIDTH_5_MHZ: + c->bandwidth_hz = 5000000; + break; + case BANDWIDTH_1_712_MHZ: + c->bandwidth_hz = 1712000; + break; + case BANDWIDTH_AUTO: c->bandwidth_hz = 0; + } + c->code_rate_HP = p->u.ofdm.code_rate_HP; c->code_rate_LP = p->u.ofdm.code_rate_LP; c->modulation = p->u.ofdm.constellation; @@ -1077,50 +1129,78 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe, c->guard_interval = p->u.ofdm.guard_interval; c->hierarchy = p->u.ofdm.hierarchy_information; break; - case FE_ATSC: + case DVBV3_ATSC: + dprintk("%s() Preparing ATSC req\n", __func__); c->modulation = p->u.vsb.modulation; if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) c->delivery_system = SYS_ATSC; else c->delivery_system = SYS_DVBC_ANNEX_B; break; + case DVBV3_UNKNOWN: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + return -EINVAL; } + + return 0; } /* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the advanced tuning API. */ -static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) +static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters *p = &fepriv->parameters_in; p->frequency = c->frequency; p->inversion = c->inversion; - switch (fe->ops.info.type) { - case FE_QPSK: + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_UNKNOWN: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + return -EINVAL; + case DVBV3_QPSK: dprintk("%s() Preparing QPSK req\n", __func__); p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; break; - case FE_QAM: + case DVBV3_QAM: dprintk("%s() Preparing QAM req\n", __func__); p->u.qam.symbol_rate = c->symbol_rate; p->u.qam.fec_inner = c->fec_inner; p->u.qam.modulation = c->modulation; break; - case FE_OFDM: + case DVBV3_OFDM: dprintk("%s() Preparing OFDM req\n", __func__); - if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 8000000) + + switch (c->bandwidth_hz) { + case 10000000: + p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ; + break; + case 8000000: p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else + break; + case 7000000: + p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + break; + case 6000000: + p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + break; + case 5000000: + p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ; + break; + case 1712000: + p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ; + break; + case 0: + default: p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + } p->u.ofdm.code_rate_HP = c->code_rate_HP; p->u.ofdm.code_rate_LP = c->code_rate_LP; p->u.ofdm.constellation = c->modulation; @@ -1128,78 +1208,40 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) p->u.ofdm.guard_interval = c->guard_interval; p->u.ofdm.hierarchy_information = c->hierarchy; break; - case FE_ATSC: + case DVBV3_ATSC: dprintk("%s() Preparing VSB req\n", __func__); p->u.vsb.modulation = c->modulation; break; } + return 0; } -/* Ensure the cached values are set correctly in the frontend - * legacy tuning structures, for the legacy tuning API. +/** + * dtv_get_frontend - calls a callback for retrieving DTV parameters + * @fe: struct dvb_frontend pointer + * @c: struct dtv_frontend_properties pointer (DVBv5 cache) + * @p_out struct dvb_frontend_parameters pointer (DVBv3 FE struct) + * + * This routine calls either the DVBv3 or DVBv5 get_frontend call. + * If c is not null, it will update the DVBv5 cache struct pointed by it. + * If p_out is not null, it will update the DVBv3 params pointed by it. */ -static void dtv_property_adv_params_sync(struct dvb_frontend *fe) +static int dtv_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out) { - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_frontend_parameters *p = &fepriv->parameters_in; - - p->frequency = c->frequency; - p->inversion = c->inversion; - - if (c->delivery_system == SYS_DSS || - c->delivery_system == SYS_DVBS || - c->delivery_system == SYS_DVBS2 || - c->delivery_system == SYS_ISDBS || - c->delivery_system == SYS_TURBO) { - p->u.qpsk.symbol_rate = c->symbol_rate; - p->u.qpsk.fec_inner = c->fec_inner; - } + int r; - /* Fake out a generic DVB-T request so we pass validation in the ioctl */ - if ((c->delivery_system == SYS_ISDBT) || - (c->delivery_system == SYS_DVBT2)) { - p->u.ofdm.constellation = QAM_AUTO; - p->u.ofdm.code_rate_HP = FEC_AUTO; - p->u.ofdm.code_rate_LP = FEC_AUTO; - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; - if (c->bandwidth_hz == 8000000) - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else - p->u.ofdm.bandwidth = BANDWIDTH_AUTO; + if (fe->ops.get_frontend) { + r = fe->ops.get_frontend(fe); + if (unlikely(r < 0)) + return r; + if (p_out) + dtv_property_legacy_params_sync(fe, p_out); + return 0; } -} - -static void dtv_property_cache_submit(struct dvb_frontend *fe) -{ - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - /* For legacy delivery systems we don't need the delivery_system to - * be specified, but we populate the older structures from the cache - * so we can call set_frontend on older drivers. - */ - if(is_legacy_delivery_system(c->delivery_system)) { - - dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation); - dtv_property_legacy_params_sync(fe); - - } else { - dprintk("%s() adv, modulation = %d\n", __func__, c->modulation); - - /* For advanced delivery systems / modulation types ... - * we seed the lecacy dvb_frontend_parameters structure - * so that the sanity checking code later in the IOCTL processing - * can validate our basic frequency ranges, symbolrates, modulation - * etc. - */ - dtv_property_adv_params_sync(fe); - } + /* As everything is in cache, get_frontend fops are always supported */ + return 0; } static int dvb_frontend_ioctl_legacy(struct file *file, @@ -1208,25 +1250,21 @@ static int dvb_frontend_ioctl_properties(struct file *file, unsigned int cmd, void *parg); static int dtv_property_process_get(struct dvb_frontend *fe, + const struct dtv_frontend_properties *c, struct dtv_property *tvp, struct file *file) { - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dtv_frontend_properties cdetected; - int r; - - /* - * If the driver implements a get_frontend function, then convert - * detected parameters to S2API properties. - */ - if (fe->ops.get_frontend) { - cdetected = *c; - dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out); - c = &cdetected; - } + int r, ncaps; switch(tvp->cmd) { + case DTV_ENUM_DELSYS: + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps]; + ncaps++; + } + tvp->u.buffer.len = ncaps; + break; case DTV_FREQUENCY: tvp->u.data = c->frequency; break; @@ -1356,14 +1394,159 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return 0; } +static int dtv_set_frontend(struct dvb_frontend *fe); + +static bool is_dvbv3_delsys(u32 delsys) +{ + bool status; + + status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) || + (delsys == SYS_DVBS) || (delsys == SYS_ATSC); + + return status; +} + +static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) +{ + int ncaps, i; + u32 delsys = SYS_UNDEFINED; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + enum dvbv3_emulation_type type; + + if (desired_system == SYS_UNDEFINED) { + /* + * A DVBv3 call doesn't know what's the desired system. + * Also, DVBv3 applications don't know that ops.info->type + * could be changed, and they simply dies when it doesn't + * match. + * So, don't change the current delivery system, as it + * may be trying to do the wrong thing, like setting an + * ISDB-T frontend as DVB-T. Instead, find the closest + * DVBv3 system that matches the delivery system. + */ + if (is_dvbv3_delsys(c->delivery_system)) { + dprintk("%s() Using delivery system to %d\n", + __func__, c->delivery_system); + return 0; + } + type = dvbv3_type(c->delivery_system); + switch (type) { + case DVBV3_QPSK: + desired_system = SYS_DVBS; + break; + case DVBV3_QAM: + desired_system = SYS_DVBC_ANNEX_A; + break; + case DVBV3_ATSC: + desired_system = SYS_ATSC; + break; + case DVBV3_OFDM: + desired_system = SYS_DVBT; + break; + default: + dprintk("%s(): This frontend doesn't support DVBv3 calls\n", + __func__); + return -EINVAL; + } + } else { + /* + * This is a DVBv5 call. So, it likely knows the supported + * delivery systems. + */ + + /* Check if the desired delivery system is supported */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if (fe->ops.delsys[ncaps] == desired_system) { + c->delivery_system = desired_system; + dprintk("%s() Changing delivery system to %d\n", + __func__, desired_system); + return 0; + } + ncaps++; + } + type = dvbv3_type(desired_system); + + /* + * The delivery system is not supported. See if it can be + * emulated. + * The emulation only works if the desired system is one of the + * DVBv3 delivery systems + */ + if (!is_dvbv3_delsys(desired_system)) { + dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n", + __func__); + return -EINVAL; + } + + /* + * Get the last non-DVBv3 delivery system that has the same type + * of the desired system + */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && + !is_dvbv3_delsys(fe->ops.delsys[ncaps])) + delsys = fe->ops.delsys[ncaps]; + ncaps++; + } + /* There's nothing compatible with the desired delivery system */ + if (delsys == SYS_UNDEFINED) { + dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", + __func__); + return -EINVAL; + } + c->delivery_system = delsys; + } + + /* + * The DVBv3 or DVBv5 call is requesting a different system. So, + * emulation is needed. + * + * Emulate newer delivery systems like ISDBT, DVBT and DMBTH + * for older DVBv5 applications. The emulation will try to use + * the auto mode for most things, and will assume that the desired + * delivery system is the last one at the ops.delsys[] array + */ + dprintk("%s() Using delivery system %d emulated as if it were a %d\n", + __func__, delsys, desired_system); + + /* + * For now, handles ISDB-T calls. More code may be needed here for the + * other emulated stuff + */ + if (type == DVBV3_OFDM) { + if (c->delivery_system == SYS_ISDBT) { + dprintk("%s() Using defaults for SYS_ISDBT\n", + __func__); + if (!c->bandwidth_hz) + c->bandwidth_hz = 6000000; + + c->isdbt_partial_reception = 0; + c->isdbt_sb_mode = 0; + c->isdbt_sb_subchannel = 0; + c->isdbt_sb_segment_idx = 0; + c->isdbt_sb_segment_count = 0; + c->isdbt_layer_enabled = 0; + for (i = 0; i < 3; i++) { + c->layer[i].fec = FEC_AUTO; + c->layer[i].modulation = QAM_AUTO; + c->layer[i].interleaving = 0; + c->layer[i].segment_count = 0; + } + } + } + dprintk("change delivery system on cache to %d\n", c->delivery_system); + + return 0; +} + static int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, struct file *file) { int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - dtv_property_dump(tvp); /* Allow the frontend to validate incoming properties */ if (fe->ops.set_property) { @@ -1374,11 +1557,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, switch(tvp->cmd) { case DTV_CLEAR: - /* Reset a cache of data specific to the frontend here. This does + /* + * Reset a cache of data specific to the frontend here. This does * not effect hardware. */ dvb_frontend_clear_cache(fe); - dprintk("%s() Flushing property cache\n", __func__); break; case DTV_TUNE: /* interpret the cache of data, build either a traditional frontend @@ -1387,10 +1570,8 @@ static int dtv_property_process_set(struct dvb_frontend *fe, */ c->state = tvp->cmd; dprintk("%s() Finalised property cache\n", __func__); - dtv_property_cache_submit(fe); - r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND, - &fepriv->parameters_in); + r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: c->frequency = tvp->u.data; @@ -1417,7 +1598,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe, c->rolloff = tvp->u.data; break; case DTV_DELIVERY_SYSTEM: - c->delivery_system = tvp->u.data; + r = set_delivery_system(fe, tvp->u.data); break; case DTV_VOLTAGE: c->voltage = tvp->u.data; @@ -1594,7 +1775,6 @@ static int dvb_frontend_ioctl_properties(struct file *file, } else if(cmd == FE_GET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; dprintk("%s() properties.num = %d\n", __func__, tvps->num); @@ -1616,8 +1796,13 @@ static int dvb_frontend_ioctl_properties(struct file *file, goto out; } + /* + * Fills the cache out struct with the cache contents, plus + * the data retrieved from get_frontend. + */ + dtv_get_frontend(fe, NULL); for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, tvp + i, file); + err = dtv_property_process_get(fe, c, tvp + i, file); if (err < 0) goto out; (tvp + i)->result = err; @@ -1636,12 +1821,121 @@ out: return err; } +static int dtv_set_frontend(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_tune_settings fetunesettings; + u32 rolloff = 0; + + if (dvb_frontend_check_parameters(fe) < 0) + return -EINVAL; + + /* + * Be sure that the bandwidth will be filled for all + * non-satellite systems, as tuners need to know what + * low pass/Nyquist half filter should be applied, in + * order to avoid inter-channel noise. + * + * ISDB-T and DVB-T/T2 already sets bandwidth. + * ATSC and DVB-C don't set, so, the core should fill it. + * + * On DVB-C Annex A and C, the bandwidth is a function of + * the roll-off and symbol rate. Annex B defines different + * roll-off factors depending on the modulation. Fortunately, + * Annex B is only used with 6MHz, so there's no need to + * calculate it. + * + * While not officially supported, a side effect of handling it at + * the cache level is that a program could retrieve the bandwidth + * via DTV_BANDWIDTH_HZ, which may be useful for test programs. + */ + switch (c->delivery_system) { + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + c->bandwidth_hz = 6000000; + break; + case SYS_DVBC_ANNEX_A: + rolloff = 115; + break; + case SYS_DVBC_ANNEX_C: + rolloff = 113; + break; + default: + break; + } + if (rolloff) + c->bandwidth_hz = (c->symbol_rate * rolloff) / 100; + + /* force auto frequency inversion if requested */ + if (dvb_force_auto_inversion) + c->inversion = INVERSION_AUTO; + + /* + * without hierarchical coding code_rate_LP is irrelevant, + * so we tolerate the otherwise invalid FEC_NONE setting + */ + if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE) + c->code_rate_LP = FEC_AUTO; + + /* get frontend-specific tuning settings */ + memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); + if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; + } else { + /* default values */ + switch (c->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + fepriv->min_delay = HZ / 20; + fepriv->step_size = c->symbol_rate / 16000; + fepriv->max_drift = c->symbol_rate / 2000; + break; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DMBTH: + fepriv->min_delay = HZ / 20; + fepriv->step_size = fe->ops.info.frequency_stepsize * 2; + fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + break; + default: + /* + * FIXME: This sounds wrong! if freqency_stepsize is + * defined by the frontend, why not use it??? + */ + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; + break; + } + } + if (dvb_override_tune_delay > 0) + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; + + fepriv->state = FESTATE_RETUNE; + + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + + dvb_frontend_clear_events(fe); + dvb_frontend_add_event(fe, 0); + dvb_frontend_wakeup(fe); + fepriv->status = 0; + + return 0; +} + + static int dvb_frontend_ioctl_legacy(struct file *file, unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int cb_err, err = -EOPNOTSUPP; if (fe->dvb->fe_ioctl_override) { @@ -1658,9 +1952,43 @@ static int dvb_frontend_ioctl_legacy(struct file *file, switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; + memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); + /* + * Associate the 4 delivery systems supported by DVBv3 + * API with their DVBv5 counterpart. For the other standards, + * use the closest type, assuming that it would hopefully + * work with a DVBv3 application. + * It should be noticed that, on multi-frontend devices with + * different types (terrestrial and cable, for example), + * a pure DVBv3 application won't be able to use all delivery + * systems. Yet, changing the DVBv5 cache to the other delivery + * system should be enough for making it work. + */ + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_QPSK: + info->type = FE_QPSK; + break; + case DVBV3_ATSC: + info->type = FE_ATSC; + break; + case DVBV3_QAM: + info->type = FE_QAM; + break; + case DVBV3_OFDM: + info->type = FE_OFDM; + break; + default: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + fe->ops.info.type = FE_OFDM; + } + dprintk("current delivery system on cache: %d, V3 type: %d\n", + c->delivery_system, fe->ops.info.type); + /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ info->caps |= FE_CAN_INVERSION_AUTO; @@ -1819,108 +2147,22 @@ static int dvb_frontend_ioctl_legacy(struct file *file, err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); break; - case FE_SET_FRONTEND: { - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_tune_settings fetunesettings; - - if (c->state == DTV_TUNE) { - if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) { - err = -EINVAL; - break; - } - } else { - if (dvb_frontend_check_parameters(fe, parg) < 0) { - err = -EINVAL; - break; - } - - memcpy (&fepriv->parameters_in, parg, - sizeof (struct dvb_frontend_parameters)); - dtv_property_cache_init(fe, c); - dtv_property_cache_sync(fe, c, &fepriv->parameters_in); - } - - /* - * Initialize output parameters to match the values given by - * the user. FE_SET_FRONTEND triggers an initial frontend event - * with status = 0, which copies output parameters to userspace. - */ - fepriv->parameters_out = fepriv->parameters_in; - - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - memcpy(&fetunesettings.parameters, parg, - sizeof (struct dvb_frontend_parameters)); - - /* force auto frequency inversion if requested */ - if (dvb_force_auto_inversion) { - fepriv->parameters_in.inversion = INVERSION_AUTO; - fetunesettings.parameters.inversion = INVERSION_AUTO; - } - if (fe->ops.info.type == FE_OFDM) { - /* without hierarchical coding code_rate_LP is irrelevant, - * so we tolerate the otherwise invalid FEC_NONE setting */ - if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE && - fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE) - fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO; - } - - /* get frontend-specific tuning settings */ - if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { - fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; - fepriv->max_drift = fetunesettings.max_drift; - fepriv->step_size = fetunesettings.step_size; - } else { - /* default values */ - switch(fe->ops.info.type) { - case FE_QPSK: - fepriv->min_delay = HZ/20; - fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000; - fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000; - break; - - case FE_QAM: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; /* no zigzag */ - fepriv->max_drift = 0; - break; - - case FE_OFDM: - fepriv->min_delay = HZ/20; - fepriv->step_size = fe->ops.info.frequency_stepsize * 2; - fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; - break; - case FE_ATSC: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; - fepriv->max_drift = 0; - break; - } - } - if (dvb_override_tune_delay > 0) - fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; - - fepriv->state = FESTATE_RETUNE; - - /* Request the search algorithm to search */ - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + case FE_SET_FRONTEND: + err = set_delivery_system(fe, SYS_UNDEFINED); + if (err) + break; - dvb_frontend_clear_events(fe); - dvb_frontend_add_event(fe, 0); - dvb_frontend_wakeup(fe); - fepriv->status = 0; - err = 0; + err = dtv_property_cache_sync(fe, c, parg); + if (err) + break; + err = dtv_set_frontend(fe); break; - } - case FE_GET_EVENT: err = dvb_frontend_get_event (fe, parg, file->f_flags); break; case FE_GET_FRONTEND: - if (fe->ops.get_frontend) { - err = fe->ops.get_frontend(fe, &fepriv->parameters_out); - memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters)); - } + err = dtv_get_frontend(fe, parg); break; case FE_SET_FRONTEND_TUNE_MODE: @@ -2061,12 +2303,15 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) dprintk ("%s\n", __func__); - if ((file->f_flags & O_ACCMODE) != O_RDONLY) + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { fepriv->release_jiffies = jiffies; + mb(); + } ret = dvb_generic_release (inode, file); if (dvbdev->users == -1) { + wake_up(&fepriv->wait_queue); if (fepriv->exit != DVB_FE_NO_EXIT) { fops_put(file->f_op); file->f_op = NULL; @@ -2127,6 +2372,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb, dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); + /* + * Initialize the cache to the proper values according with the + * first supported delivery system (ops->delsys[0]) + */ + + fe->dtv_property_cache.delivery_system = fe->ops.delsys[0]; + dvb_frontend_clear_cache(fe); + mutex_unlock(&frontend_mutex); return 0; } diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 67bbfa728016..d63a8215fe03 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -42,11 +42,16 @@ #include "dvbdev.h" +/* + * Maximum number of Delivery systems per frontend. It + * should be smaller or equal to 32 + */ +#define MAX_DELSYS 8 + struct dvb_frontend_tune_settings { int min_delay_ms; int step_size; int max_drift; - struct dvb_frontend_parameters parameters; }; struct dvb_frontend; @@ -198,11 +203,11 @@ struct dvb_tuner_ops { int (*sleep)(struct dvb_frontend *fe); /** This is for simple PLLs - set all parameters in one go. */ - int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + int (*set_params)(struct dvb_frontend *fe); int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ - int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len); /** This is to allow setting tuner-specific configs */ int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); @@ -250,10 +255,14 @@ struct analog_demod_ops { int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); }; +struct dtv_frontend_properties; + struct dvb_frontend_ops { struct dvb_frontend_info info; + u8 delsys[MAX_DELSYS]; + void (*release)(struct dvb_frontend* fe); void (*release_sec)(struct dvb_frontend* fe); @@ -264,7 +273,7 @@ struct dvb_frontend_ops { /* if this is set, it overrides the default swzigzag */ int (*tune)(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status); @@ -272,10 +281,10 @@ struct dvb_frontend_ops { enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); /* these two are only used for the swzigzag code */ - int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*set_frontend)(struct dvb_frontend *fe); int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); - int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*get_frontend)(struct dvb_frontend *fe); int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); int (*read_ber)(struct dvb_frontend* fe, u32* ber); @@ -297,8 +306,7 @@ struct dvb_frontend_ops { /* These callbacks are for devices that implement their own * tuning algorithms, rather than a simple swzigzag */ - enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); - int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + enum dvbfe_search (*search)(struct dvb_frontend *fe); struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; @@ -307,6 +315,7 @@ struct dvb_frontend_ops { int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); }; +#ifdef __DVB_CORE__ #define MAX_EVENT 8 struct dvb_fe_events { @@ -317,6 +326,7 @@ struct dvb_fe_events { wait_queue_head_t wait_queue; struct mutex mtx; }; +#endif struct dtv_frontend_properties { @@ -374,6 +384,7 @@ struct dvb_frontend { void *analog_demod_priv; struct dtv_frontend_properties dtv_property_cache; #define DVB_FRONTEND_COMPONENT_TUNER 0 +#define DVB_FRONTEND_COMPONENT_DEMOD 1 int (*callback)(void *adapter_priv, int component, int cmd, int arg); int id; }; diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 93d9869e0f15..8766ce8c354d 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1510,9 +1510,7 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, for (i=0; i<DVB_NET_DEVICES_MAX; i++) dvbnet->state[i] = 0; - dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, + return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net, dvbnet, DVB_DEVICE_NET); - - return 0; } EXPORT_SYMBOL(dvb_net_init); diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 58257165761e..9f203c6767a6 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -311,6 +311,7 @@ config DVB_USB_ANYSEE select DVB_STV0900 if !DVB_FE_CUSTOMISE select DVB_STV6110 if !DVB_FE_CUSTOMISE select DVB_ISL6423 if !DVB_FE_CUSTOMISE + select DVB_CXD2820R if !DVB_FE_CUSTOMISE help Say Y here to support the Anysee E30, Anysee E30 Plus or Anysee E30 C Plus DVB USB2.0 receiver. @@ -340,7 +341,7 @@ config DVB_USB_AF9015 config DVB_USB_CE6230 tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB && EXPERIMENTAL + depends on DVB_USB select DVB_ZL10353 select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help @@ -354,7 +355,7 @@ config DVB_USB_FRIIO config DVB_USB_EC168 tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB && EXPERIMENTAL + depends on DVB_USB select DVB_EC100 select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE help diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c index 3263e9749d09..740f3f496f12 100644 --- a/drivers/media/dvb/dvb-usb/af9005-fe.c +++ b/drivers/media/dvb/dvb-usb/af9005-fe.c @@ -303,7 +303,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, return -EINVAL; } - /* read constellation mode */ + /* read modulation mode */ ret = af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, reg_tpsd_const_pos, reg_tpsd_const_len, @@ -321,7 +321,7 @@ static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, bits = 6; break; default: - err("invalid constellation mode"); + err("invalid modulation mode"); return -EINVAL; } *pre_bit_count = super_frame_count * 68 * 4 * x * bits; @@ -533,13 +533,13 @@ static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr) { - /* the snr can be derived from the ber and the constellation + /* the snr can be derived from the ber and the modulation but I don't think this kind of complex calculations belong in the driver. I may be wrong.... */ return -ENOSYS; } -static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) +static int af9005_fe_program_cfoe(struct dvb_usb_device *d, u32 bw) { u8 temp0, temp1, temp2, temp3, buf[4]; int ret; @@ -551,7 +551,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) u32 NS_coeff2_8k; switch (bw) { - case BANDWIDTH_6_MHZ: + case 6000000: NS_coeff1_2048Nu = 0x2ADB6DC; NS_coeff1_8191Nu = 0xAB7313; NS_coeff1_8192Nu = 0xAB6DB7; @@ -560,7 +560,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) NS_coeff2_8k = 0x55B6DC; break; - case BANDWIDTH_7_MHZ: + case 7000000: NS_coeff1_2048Nu = 0x3200001; NS_coeff1_8191Nu = 0xC80640; NS_coeff1_8192Nu = 0xC80000; @@ -569,7 +569,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) NS_coeff2_8k = 0x640000; break; - case BANDWIDTH_8_MHZ: + case 8000000: NS_coeff1_2048Nu = 0x3924926; NS_coeff1_8191Nu = 0xE4996E; NS_coeff1_8192Nu = 0xE49249; @@ -773,17 +773,17 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) } -static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw) +static int af9005_fe_select_bw(struct dvb_usb_device *d, u32 bw) { u8 temp; switch (bw) { - case BANDWIDTH_6_MHZ: + case 6000000: temp = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: temp = 1; break; - case BANDWIDTH_8_MHZ: + case 8000000: temp = 2; break; default: @@ -930,10 +930,11 @@ static int af9005_fe_init(struct dvb_frontend *fe) /* init other parameters: program cfoe and select bandwidth */ deb_info("program cfoe\n"); - if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ))) + ret = af9005_fe_program_cfoe(state->d, 6000000); + if (ret) return ret; - /* set read-update bit for constellation */ - deb_info("set read-update bit for constellation\n"); + /* set read-update bit for modulation */ + deb_info("set read-update bit for modulation\n"); if ((ret = af9005_write_register_bits(state->d, xd_p_reg_feq_read_update, reg_feq_read_update_pos, @@ -943,8 +944,8 @@ static int af9005_fe_init(struct dvb_frontend *fe) /* sample code has a set MPEG TS code here but sniffing reveals that it doesn't do it */ - /* set read-update bit to 1 for DCA constellation */ - deb_info("set read-update bit 1 for DCA constellation\n"); + /* set read-update bit to 1 for DCA modulation */ + deb_info("set read-update bit 1 for DCA modulation\n"); if ((ret = af9005_write_register_bits(state->d, xd_p_reg_dca_read_update, reg_dca_read_update_pos, @@ -1099,15 +1100,15 @@ static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) return 0; } -static int af9005_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int af9005_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct af9005_fe_state *state = fe->demodulator_priv; int ret; u8 temp, temp0, temp1, temp2; deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency, - fep->u.ofdm.bandwidth); + fep->bandwidth_hz); if (fe->ops.tuner_ops.release == NULL) { err("Tuner not attached"); return -ENODEV; @@ -1167,10 +1168,10 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, /* select bandwidth */ deb_info("select bandwidth"); - ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth); + ret = af9005_fe_select_bw(state->d, fep->bandwidth_hz); if (ret) return ret; - ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth); + ret = af9005_fe_program_cfoe(state->d, fep->bandwidth_hz); if (ret) return ret; @@ -1189,7 +1190,7 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, return ret; /* set tuner */ deb_info("set tuner\n"); - ret = fe->ops.tuner_ops.set_params(fe, fep); + ret = fe->ops.tuner_ops.set_params(fe); if (ret) return ret; @@ -1225,9 +1226,9 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, return 0; } -static int af9005_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int af9005_fe_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct af9005_fe_state *state = fe->demodulator_priv; int ret; u8 temp; @@ -1239,19 +1240,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, &temp); if (ret) return ret; - deb_info("===== fe_get_frontend ==============\n"); + deb_info("===== fe_get_frontend_legacy = =============\n"); deb_info("CONSTELLATION "); switch (temp) { case 0: - fep->u.ofdm.constellation = QPSK; + fep->modulation = QPSK; deb_info("QPSK\n"); break; case 1: - fep->u.ofdm.constellation = QAM_16; + fep->modulation = QAM_16; deb_info("QAM_16\n"); break; case 2: - fep->u.ofdm.constellation = QAM_64; + fep->modulation = QAM_64; deb_info("QAM_64\n"); break; } @@ -1266,19 +1267,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("HIERARCHY "); switch (temp) { case 0: - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; deb_info("NONE\n"); break; case 1: - fep->u.ofdm.hierarchy_information = HIERARCHY_1; + fep->hierarchy = HIERARCHY_1; deb_info("1\n"); break; case 2: - fep->u.ofdm.hierarchy_information = HIERARCHY_2; + fep->hierarchy = HIERARCHY_2; deb_info("2\n"); break; case 3: - fep->u.ofdm.hierarchy_information = HIERARCHY_4; + fep->hierarchy = HIERARCHY_4; deb_info("4\n"); break; } @@ -1302,23 +1303,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("CODERATE HP "); switch (temp) { case 0: - fep->u.ofdm.code_rate_HP = FEC_1_2; + fep->code_rate_HP = FEC_1_2; deb_info("FEC_1_2\n"); break; case 1: - fep->u.ofdm.code_rate_HP = FEC_2_3; + fep->code_rate_HP = FEC_2_3; deb_info("FEC_2_3\n"); break; case 2: - fep->u.ofdm.code_rate_HP = FEC_3_4; + fep->code_rate_HP = FEC_3_4; deb_info("FEC_3_4\n"); break; case 3: - fep->u.ofdm.code_rate_HP = FEC_5_6; + fep->code_rate_HP = FEC_5_6; deb_info("FEC_5_6\n"); break; case 4: - fep->u.ofdm.code_rate_HP = FEC_7_8; + fep->code_rate_HP = FEC_7_8; deb_info("FEC_7_8\n"); break; } @@ -1333,23 +1334,23 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("CODERATE LP "); switch (temp) { case 0: - fep->u.ofdm.code_rate_LP = FEC_1_2; + fep->code_rate_LP = FEC_1_2; deb_info("FEC_1_2\n"); break; case 1: - fep->u.ofdm.code_rate_LP = FEC_2_3; + fep->code_rate_LP = FEC_2_3; deb_info("FEC_2_3\n"); break; case 2: - fep->u.ofdm.code_rate_LP = FEC_3_4; + fep->code_rate_LP = FEC_3_4; deb_info("FEC_3_4\n"); break; case 3: - fep->u.ofdm.code_rate_LP = FEC_5_6; + fep->code_rate_LP = FEC_5_6; deb_info("FEC_5_6\n"); break; case 4: - fep->u.ofdm.code_rate_LP = FEC_7_8; + fep->code_rate_LP = FEC_7_8; deb_info("FEC_7_8\n"); break; } @@ -1363,19 +1364,19 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("GUARD INTERVAL "); switch (temp) { case 0: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + fep->guard_interval = GUARD_INTERVAL_1_32; deb_info("1_32\n"); break; case 1: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + fep->guard_interval = GUARD_INTERVAL_1_16; deb_info("1_16\n"); break; case 2: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + fep->guard_interval = GUARD_INTERVAL_1_8; deb_info("1_8\n"); break; case 3: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + fep->guard_interval = GUARD_INTERVAL_1_4; deb_info("1_4\n"); break; } @@ -1390,11 +1391,11 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("TRANSMISSION MODE "); switch (temp) { case 0: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + fep->transmission_mode = TRANSMISSION_MODE_2K; deb_info("2K\n"); break; case 1: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + fep->transmission_mode = TRANSMISSION_MODE_8K; deb_info("8K\n"); break; } @@ -1406,15 +1407,15 @@ static int af9005_fe_get_frontend(struct dvb_frontend *fe, deb_info("BANDWIDTH "); switch (temp) { case 0: - fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + fep->bandwidth_hz = 6000000; deb_info("6\n"); break; case 1: - fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + fep->bandwidth_hz = 7000000; deb_info("7\n"); break; case 2: - fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fep->bandwidth_hz = 8000000; deb_info("8\n"); break; } @@ -1454,9 +1455,9 @@ struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) } static struct dvb_frontend_ops af9005_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "AF9005 USB DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 250000, diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index bd51a764351b..af176b6ce738 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))." DVB_USB_DEBUG_STATUS); /* enable obnoxious led */ -int dvb_usb_af9005_led = 1; +bool dvb_usb_af9005_led = 1; module_param_named(led, dvb_usb_af9005_led, bool, 0644); MODULE_PARM_DESC(led, "enable led (default: 1)."); @@ -977,11 +977,20 @@ static int af9005_usb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr); } +enum af9005_usb_table_entry { + AFATECH_AF9005, + TERRATEC_AF9005, + ANSONIC_AF9005, +}; + static struct usb_device_id af9005_usb_table[] = { - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, - {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, - {0}, + [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH, + USB_PID_AFATECH_AF9005)}, + [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC, + USB_PID_ANSONIC_DVBT_USB)}, + { } }; MODULE_DEVICE_TABLE(usb, af9005_usb_table); @@ -1041,15 +1050,15 @@ static struct dvb_usb_device_properties af9005_properties = { .num_device_descs = 3, .devices = { {.name = "Afatech DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[0], NULL}, + .cold_ids = {&af9005_usb_table[AFATECH_AF9005], NULL}, .warm_ids = {NULL}, }, {.name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9005_usb_table[1], NULL}, + .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL}, .warm_ids = {NULL}, }, {.name = "Ansonic DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[2], NULL}, + .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL}, .warm_ids = {NULL}, }, {NULL}, diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h index c71c77bd7f4b..6a2bf3de8456 100644 --- a/drivers/media/dvb/dvb-usb/af9005.h +++ b/drivers/media/dvb/dvb-usb/af9005.h @@ -35,7 +35,7 @@ extern int dvb_usb_af9005_debug; #define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args) #define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args) -extern int dvb_usb_af9005_led; +extern bool dvb_usb_af9005_led; /* firmware */ #define FW_BULKOUT_SIZE 250 diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 56cbd3636c31..282a43d648df 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -50,14 +50,14 @@ static int af9015_properties_count = ARRAY_SIZE(af9015_properties); static struct af9013_config af9015_af9013_config[] = { { - .demod_address = AF9015_I2C_DEMOD, - .output_mode = AF9013_OUTPUT_MODE_USB, + .i2c_addr = AF9015_I2C_DEMOD, + .ts_mode = AF9013_TS_USB, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_HI, .gpio[3] = AF9013_GPIO_TUNER_ON, }, { - .output_mode = AF9013_OUTPUT_MODE_SERIAL, + .ts_mode = AF9013_TS_SERIAL, .api_version = { 0, 1, 9, 0 }, .gpio[0] = AF9013_GPIO_TUNER_ON, .gpio[1] = AF9013_GPIO_LO, @@ -216,8 +216,8 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, { struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - if (addr == af9015_af9013_config[0].demod_address || - addr == af9015_af9013_config[1].demod_address) + if (addr == af9015_af9013_config[0].i2c_addr || + addr == af9015_af9013_config[1].i2c_addr) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -228,8 +228,8 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, { struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - if (addr == af9015_af9013_config[0].demod_address || - addr == af9015_af9013_config[1].demod_address) + if (addr == af9015_af9013_config[0].i2c_addr || + addr == af9015_af9013_config[1].i2c_addr) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -271,8 +271,8 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. return -EAGAIN; while (i < num) { - if (msg[i].addr == af9015_af9013_config[0].demod_address || - msg[i].addr == af9015_af9013_config[1].demod_address) { + if (msg[i].addr == af9015_af9013_config[0].i2c_addr || + msg[i].addr == af9015_af9013_config[1].i2c_addr) { addr = msg[i].buf[0] << 8; addr += msg[i].buf[1]; mbox = msg[i].buf[2]; @@ -288,8 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == - af9015_af9013_config[0].demod_address) + if (msg[i].addr == af9015_af9013_config[0].i2c_addr) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; @@ -307,7 +306,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. goto error; } if (msg[i].addr == - af9015_af9013_config[0].demod_address) { + af9015_af9013_config[0].i2c_addr) { ret = -EINVAL; goto error; } @@ -325,8 +324,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto error; } - if (msg[i].addr == - af9015_af9013_config[0].demod_address) + if (msg[i].addr == af9015_af9013_config[0].i2c_addr) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; @@ -508,7 +506,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) msleep(100); ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].demod_address, 0x98be, &val); + af9015_af9013_config[1].i2c_addr, 0x98be, &val); if (ret) goto error; else @@ -536,7 +534,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) goto error; /* request boot firmware */ - ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].demod_address, + ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].i2c_addr, 0xe205, 1); deb_info("%s: firmware boot cmd status:%d\n", __func__, ret); if (ret) @@ -547,7 +545,7 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) /* check firmware status */ ret = af9015_read_reg_i2c(d, - af9015_af9013_config[1].demod_address, 0x98be, &val); + af9015_af9013_config[1].i2c_addr, 0x98be, &val); deb_info("%s: firmware status cmd status:%d fw status:%02x\n", __func__, ret, val); if (ret) @@ -840,7 +838,7 @@ static int af9015_read_config(struct usb_device *udev) if (ret) goto error; - deb_info("%s: IR mode:%d\n", __func__, val); + deb_info("%s: IR mode=%d\n", __func__, val); for (i = 0; i < af9015_properties_count; i++) { if (val == AF9015_IR_MODE_DISABLED) af9015_properties[i].rc.core.rc_codes = NULL; @@ -854,7 +852,7 @@ static int af9015_read_config(struct usb_device *udev) if (ret) goto error; af9015_config.dual_mode = val; - deb_info("%s: TS mode:%d\n", __func__, af9015_config.dual_mode); + deb_info("%s: TS mode=%d\n", __func__, af9015_config.dual_mode); /* Set adapter0 buffer size according to USB port speed, adapter1 buffer size can be static because it is enabled only USB2.0 */ @@ -878,7 +876,7 @@ static int af9015_read_config(struct usb_device *udev) ret = af9015_rw_udev(udev, &req); if (ret) goto error; - af9015_af9013_config[1].demod_address = val; + af9015_af9013_config[1].i2c_addr = val; /* enable 2nd adapter */ for (i = 0; i < af9015_properties_count; i++) @@ -900,34 +898,38 @@ static int af9015_read_config(struct usb_device *udev) goto error; switch (val) { case 0: - af9015_af9013_config[i].adc_clock = 28800; + af9015_af9013_config[i].clock = 28800000; break; case 1: - af9015_af9013_config[i].adc_clock = 20480; + af9015_af9013_config[i].clock = 20480000; break; case 2: - af9015_af9013_config[i].adc_clock = 28000; + af9015_af9013_config[i].clock = 28000000; break; case 3: - af9015_af9013_config[i].adc_clock = 25000; + af9015_af9013_config[i].clock = 25000000; break; }; - deb_info("%s: [%d] xtal:%d set adc_clock:%d\n", __func__, i, - val, af9015_af9013_config[i].adc_clock); + deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i, + val, af9015_af9013_config[i].clock); - /* tuner IF */ + /* IF frequency */ req.addr = AF9015_EEPROM_IF1H + offset; ret = af9015_rw_udev(udev, &req); if (ret) goto error; - af9015_af9013_config[i].tuner_if = val << 8; + + af9015_af9013_config[i].if_frequency = val << 8; + req.addr = AF9015_EEPROM_IF1L + offset; ret = af9015_rw_udev(udev, &req); if (ret) goto error; - af9015_af9013_config[i].tuner_if += val; - deb_info("%s: [%d] IF1:%d\n", __func__, i, - af9015_af9013_config[0].tuner_if); + + af9015_af9013_config[i].if_frequency += val; + af9015_af9013_config[i].if_frequency *= 1000; + deb_info("%s: [%d] IF frequency=%d\n", __func__, i, + af9015_af9013_config[0].if_frequency); /* MT2060 IF1 */ req.addr = AF9015_EEPROM_MT2060_IF1H + offset; @@ -940,7 +942,7 @@ static int af9015_read_config(struct usb_device *udev) if (ret) goto error; af9015_config.mt2060_if1[i] += val; - deb_info("%s: [%d] MT2060 IF1:%d\n", __func__, i, + deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i, af9015_config.mt2060_if1[i]); /* tuner */ @@ -957,30 +959,30 @@ static int af9015_read_config(struct usb_device *udev) case AF9013_TUNER_TDA18271: case AF9013_TUNER_QT1010A: case AF9013_TUNER_TDA18218: - af9015_af9013_config[i].rf_spec_inv = 1; + af9015_af9013_config[i].spec_inv = 1; break; case AF9013_TUNER_MXL5003D: case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - af9015_af9013_config[i].rf_spec_inv = 0; + af9015_af9013_config[i].spec_inv = 0; break; case AF9013_TUNER_MC44S803: af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO; - af9015_af9013_config[i].rf_spec_inv = 1; + af9015_af9013_config[i].spec_inv = 1; break; default: - warn("tuner id:%d not supported, please report!", val); + warn("tuner id=%d not supported, please report!", val); return -ENODEV; }; af9015_af9013_config[i].tuner = val; - deb_info("%s: [%d] tuner id:%d\n", __func__, i, val); + deb_info("%s: [%d] tuner id=%d\n", __func__, i, val); } error: if (ret) - err("eeprom read failed:%d", ret); + err("eeprom read failed=%d", ret); /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM content :-( Override some wrong values here. Ditto for the @@ -998,7 +1000,7 @@ error: af9015_properties[i].num_adapters = 1; /* set correct IF */ - af9015_af9013_config[0].tuner_if = 4570; + af9015_af9013_config[0].if_frequency = 4570000; } return ret; @@ -1093,9 +1095,79 @@ error: return ret; } +/* override demod callbacks for resource locking */ +static int af9015_af9013_set_frontend(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->set_frontend[adap->id](fe); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_read_status(struct dvb_frontend *fe, + fe_status_t *status) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->read_status[adap->id](fe, status); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_init(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->init[adap->id](fe); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + +/* override demod callbacks for resource locking */ +static int af9015_af9013_sleep(struct dvb_frontend *fe) +{ + int ret; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct af9015_state *priv = adap->dev->priv; + + if (mutex_lock_interruptible(&adap->dev->usb_mutex)) + return -EAGAIN; + + ret = priv->sleep[adap->id](fe); + + mutex_unlock(&adap->dev->usb_mutex); + + return ret; +} + static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) { int ret; + struct af9015_state *state = adap->dev->priv; if (adap->id == 1) { /* copy firmware to 2nd demodulator */ @@ -1116,6 +1188,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); + /* + * AF9015 firmware does not like if it gets interrupted by I2C adapter + * request on some critical phases. During normal operation I2C adapter + * is used only 2nd demodulator and tuner on dual tuner devices. + * Override demodulator callbacks and use mutex for limit access to + * those "critical" paths to keep AF9015 happy. + * Note: we abuse unused usb_mutex here. + */ + if (adap->fe_adap[0].fe) { + state->set_frontend[adap->id] = + adap->fe_adap[0].fe->ops.set_frontend; + adap->fe_adap[0].fe->ops.set_frontend = + af9015_af9013_set_frontend; + + state->read_status[adap->id] = + adap->fe_adap[0].fe->ops.read_status; + adap->fe_adap[0].fe->ops.read_status = + af9015_af9013_read_status; + + state->init[adap->id] = adap->fe_adap[0].fe->ops.init; + adap->fe_adap[0].fe->ops.init = af9015_af9013_init; + + state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep; + adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep; + } + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -1245,49 +1343,112 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) return ret; } +enum af9015_usb_table_entry { + AFATECH_9015, + AFATECH_9016, + WINFAST_DTV_GOLD, + PINNACLE_PCTV_71E, + KWORLD_PLUSTV_399U, + TINYTWIN, + AZUREWAVE_TU700, + TERRATEC_AF9015, + KWORLD_PLUSTV_PC160, + AVERTV_VOLAR_X, + XTENSIONS_380U, + MSI_DIGIVOX_DUO, + AVERTV_VOLAR_X_REV2, + TELESTAR_STARSTICK_2, + AVERMEDIA_A309_USB, + MSI_DIGIVOX_MINI_III, + KWORLD_E396, + KWORLD_E39B, + KWORLD_E395, + TREKSTOR_DVBT, + AVERTV_A850, + AVERTV_A805, + CONCEPTRONIC_CTVDIGRCU, + KWORLD_MC810, + GENIUS_TVGO_DVB_T03, + KWORLD_399U_2, + KWORLD_PC160_T, + SVEON_STV20, + TINYTWIN_2, + WINFAST_DTV2000DS, + KWORLD_UB383_T, + KWORLD_E39A, + AVERMEDIA_A815M, + CINERGY_T_STICK_RC, + CINERGY_T_DUAL_RC, + AVERTV_A850T, + TINYTWIN_3, + SVEON_STV22, +}; + static struct usb_device_id af9015_usb_table[] = { -/* 0 */{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, - {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, - {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, -/* 5 */{USB_DEVICE(USB_VID_VISIONPLUS, - USB_PID_TINYTWIN)}, - {USB_DEVICE(USB_VID_VISIONPLUS, - USB_PID_AZUREWAVE_AD_TU700)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, -/* 10 */{USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, - {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, - {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, -/* 15 */{USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, - {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, -/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, - {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, -/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, - {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, -/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, - {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, - {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, -/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, - {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, - {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, - {0}, + [AFATECH_9015] = + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)}, + [AFATECH_9016] = + {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)}, + [WINFAST_DTV_GOLD] = + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)}, + [PINNACLE_PCTV_71E] = + {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)}, + [KWORLD_PLUSTV_399U] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)}, + [TINYTWIN] = {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)}, + [AZUREWAVE_TU700] = + {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)}, + [TERRATEC_AF9015] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)}, + [KWORLD_PLUSTV_PC160] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)}, + [AVERTV_VOLAR_X] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)}, + [XTENSIONS_380U] = + {USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)}, + [MSI_DIGIVOX_DUO] = + {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)}, + [AVERTV_VOLAR_X_REV2] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)}, + [TELESTAR_STARSTICK_2] = + {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)}, + [AVERMEDIA_A309_USB] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)}, + [MSI_DIGIVOX_MINI_III] = + {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)}, + [KWORLD_E396] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)}, + [KWORLD_E39B] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)}, + [KWORLD_E395] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)}, + [TREKSTOR_DVBT] = {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)}, + [AVERTV_A850] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)}, + [AVERTV_A805] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)}, + [CONCEPTRONIC_CTVDIGRCU] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)}, + [KWORLD_MC810] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)}, + [GENIUS_TVGO_DVB_T03] = + {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)}, + [KWORLD_399U_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)}, + [KWORLD_PC160_T] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)}, + [SVEON_STV20] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)}, + [TINYTWIN_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)}, + [WINFAST_DTV2000DS] = + {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)}, + [KWORLD_UB383_T] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)}, + [KWORLD_E39A] = + {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)}, + [AVERMEDIA_A815M] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)}, + [CINERGY_T_STICK_RC] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_STICK_RC)}, + [CINERGY_T_DUAL_RC] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)}, + [AVERTV_A850T] = + {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)}, + [TINYTWIN_3] = {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)}, + [SVEON_STV22] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)}, + { } }; MODULE_DEVICE_TABLE(usb, af9015_usb_table); @@ -1362,68 +1523,104 @@ static struct dvb_usb_device_properties af9015_properties[] = { .devices = { { .name = "Afatech AF9015 DVB-T USB2.0 stick", - .cold_ids = {&af9015_usb_table[0], - &af9015_usb_table[1], NULL}, + .cold_ids = { + &af9015_usb_table[AFATECH_9015], + &af9015_usb_table[AFATECH_9016], + NULL + }, .warm_ids = {NULL}, }, { .name = "Leadtek WinFast DTV Dongle Gold", - .cold_ids = {&af9015_usb_table[2], NULL}, + .cold_ids = { + &af9015_usb_table[WINFAST_DTV_GOLD], + NULL + }, .warm_ids = {NULL}, }, { .name = "Pinnacle PCTV 71e", - .cold_ids = {&af9015_usb_table[3], NULL}, + .cold_ids = { + &af9015_usb_table[PINNACLE_PCTV_71E], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV Dual DVB-T Stick " \ "(DVB-T 399U)", - .cold_ids = {&af9015_usb_table[4], - &af9015_usb_table[25], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_PLUSTV_399U], + &af9015_usb_table[KWORLD_399U_2], + NULL + }, .warm_ids = {NULL}, }, { .name = "DigitalNow TinyTwin DVB-T Receiver", - .cold_ids = {&af9015_usb_table[5], - &af9015_usb_table[28], - &af9015_usb_table[36], NULL}, + .cold_ids = { + &af9015_usb_table[TINYTWIN], + &af9015_usb_table[TINYTWIN_2], + &af9015_usb_table[TINYTWIN_3], + NULL + }, .warm_ids = {NULL}, }, { .name = "TwinHan AzureWave AD-TU700(704J)", - .cold_ids = {&af9015_usb_table[6], NULL}, + .cold_ids = { + &af9015_usb_table[AZUREWAVE_TU700], + NULL + }, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9015_usb_table[7], NULL}, + .cold_ids = { + &af9015_usb_table[TERRATEC_AF9015], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV Dual DVB-T PCI " \ "(DVB-T PC160-2T)", - .cold_ids = {&af9015_usb_table[8], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_PLUSTV_PC160], + NULL + }, .warm_ids = {NULL}, }, { .name = "AVerMedia AVerTV DVB-T Volar X", - .cold_ids = {&af9015_usb_table[9], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_VOLAR_X], + NULL + }, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T Stick RC", - .cold_ids = {&af9015_usb_table[33], NULL}, + .cold_ids = { + &af9015_usb_table[CINERGY_T_STICK_RC], + NULL + }, .warm_ids = {NULL}, }, { .name = "TerraTec Cinergy T Stick Dual RC", - .cold_ids = {&af9015_usb_table[34], NULL}, + .cold_ids = { + &af9015_usb_table[CINERGY_T_DUAL_RC], + NULL + }, .warm_ids = {NULL}, }, { .name = "AverMedia AVerTV Red HD+ (A850T)", - .cold_ids = {&af9015_usb_table[35], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_A850T], + NULL + }, .warm_ids = {NULL}, }, } @@ -1496,57 +1693,87 @@ static struct dvb_usb_device_properties af9015_properties[] = { .devices = { { .name = "Xtensions XD-380", - .cold_ids = {&af9015_usb_table[10], NULL}, + .cold_ids = { + &af9015_usb_table[XTENSIONS_380U], + NULL + }, .warm_ids = {NULL}, }, { .name = "MSI DIGIVOX Duo", - .cold_ids = {&af9015_usb_table[11], NULL}, + .cold_ids = { + &af9015_usb_table[MSI_DIGIVOX_DUO], + NULL + }, .warm_ids = {NULL}, }, { .name = "Fujitsu-Siemens Slim Mobile USB DVB-T", - .cold_ids = {&af9015_usb_table[12], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_VOLAR_X_REV2], + NULL + }, .warm_ids = {NULL}, }, { .name = "Telestar Starstick 2", - .cold_ids = {&af9015_usb_table[13], NULL}, + .cold_ids = { + &af9015_usb_table[TELESTAR_STARSTICK_2], + NULL + }, .warm_ids = {NULL}, }, { .name = "AVerMedia A309", - .cold_ids = {&af9015_usb_table[14], NULL}, + .cold_ids = { + &af9015_usb_table[AVERMEDIA_A309_USB], + NULL + }, .warm_ids = {NULL}, }, { .name = "MSI Digi VOX mini III", - .cold_ids = {&af9015_usb_table[15], NULL}, + .cold_ids = { + &af9015_usb_table[MSI_DIGIVOX_MINI_III], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld USB DVB-T TV Stick II " \ "(VS-DVB-T 395U)", - .cold_ids = {&af9015_usb_table[16], - &af9015_usb_table[17], - &af9015_usb_table[18], - &af9015_usb_table[31], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_E396], + &af9015_usb_table[KWORLD_E39B], + &af9015_usb_table[KWORLD_E395], + &af9015_usb_table[KWORLD_E39A], + NULL + }, .warm_ids = {NULL}, }, { .name = "TrekStor DVB-T USB Stick", - .cold_ids = {&af9015_usb_table[19], NULL}, + .cold_ids = { + &af9015_usb_table[TREKSTOR_DVBT], + NULL + }, .warm_ids = {NULL}, }, { .name = "AverMedia AVerTV Volar Black HD " \ "(A850)", - .cold_ids = {&af9015_usb_table[20], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_A850], + NULL + }, .warm_ids = {NULL}, }, { .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV", - .cold_ids = {&af9015_usb_table[37], NULL}, + .cold_ids = { + &af9015_usb_table[SVEON_STV22], + NULL + }, .warm_ids = {NULL}, }, } @@ -1619,50 +1846,77 @@ static struct dvb_usb_device_properties af9015_properties[] = { .devices = { { .name = "AverMedia AVerTV Volar GPS 805 (A805)", - .cold_ids = {&af9015_usb_table[21], NULL}, + .cold_ids = { + &af9015_usb_table[AVERTV_A805], + NULL + }, .warm_ids = {NULL}, }, { .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \ "V3.0", - .cold_ids = {&af9015_usb_table[22], NULL}, + .cold_ids = { + &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld Digial MC-810", - .cold_ids = {&af9015_usb_table[23], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_MC810], + NULL + }, .warm_ids = {NULL}, }, { .name = "Genius TVGo DVB-T03", - .cold_ids = {&af9015_usb_table[24], NULL}, + .cold_ids = { + &af9015_usb_table[GENIUS_TVGO_DVB_T03], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld PlusTV DVB-T PCI Pro Card " \ "(DVB-T PC160-T)", - .cold_ids = {&af9015_usb_table[26], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_PC160_T], + NULL + }, .warm_ids = {NULL}, }, { .name = "Sveon STV20 Tuner USB DVB-T HDTV", - .cold_ids = {&af9015_usb_table[27], NULL}, + .cold_ids = { + &af9015_usb_table[SVEON_STV20], + NULL + }, .warm_ids = {NULL}, }, { .name = "Leadtek WinFast DTV2000DS", - .cold_ids = {&af9015_usb_table[29], NULL}, + .cold_ids = { + &af9015_usb_table[WINFAST_DTV2000DS], + NULL + }, .warm_ids = {NULL}, }, { .name = "KWorld USB DVB-T Stick Mobile " \ "(UB383-T)", - .cold_ids = {&af9015_usb_table[30], NULL}, + .cold_ids = { + &af9015_usb_table[KWORLD_UB383_T], + NULL + }, .warm_ids = {NULL}, }, { .name = "AverMedia AVerTV Volar M (A815Mac)", - .cold_ids = {&af9015_usb_table[32], NULL}, + .cold_ids = { + &af9015_usb_table[AVERMEDIA_A815M], + NULL + }, .warm_ids = {NULL}, }, } diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index 6252ea6c1904..f619063fa72f 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -102,6 +102,12 @@ struct af9015_state { u8 rc_repeat; u32 rc_keycode; u8 rc_last[4]; + + /* for demod callback override */ + int (*set_frontend[2]) (struct dvb_frontend *fe); + int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status); + int (*init[2]) (struct dvb_frontend *fe); + int (*sleep[2]) (struct dvb_frontend *fe); }; struct af9015_config { diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index b39f14f85e71..d66192974d68 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -41,6 +41,7 @@ #include "stv0900.h" #include "stv6110.h" #include "isl6423.h" +#include "cxd2820r.h" /* debug */ static int dvb_usb_anysee_debug; @@ -66,10 +67,12 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) return -EAGAIN; + deb_xfer(">>> "); + debug_dump(buf, slen, deb_xfer); + /* We need receive one message more after dvb_usb_generic_rw due to weird transaction flow, which is 1 x send + 2 x receive. */ ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); - if (!ret) { /* receive 2nd answer */ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, @@ -79,7 +82,10 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, err("%s: recv bulk message failed: %d", __func__, ret); else { deb_xfer("<<< "); - debug_dump(buf, act_len, deb_xfer); + debug_dump(buf, rlen, deb_xfer); + + if (buf[63] != 0x4f) + deb_info("%s: cmd failed\n", __func__); } } @@ -129,6 +135,29 @@ static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, return anysee_write_reg(d, reg, val); } +/* read single register with mask */ +static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, + u8 mask) +{ + int ret, i; + u8 tmp; + + ret = anysee_read_reg(d, reg, &tmp); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) { u8 buf[] = {CMD_GET_HW_INFO}; @@ -156,22 +185,6 @@ static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } -static int anysee_init(struct dvb_usb_device *d) -{ - int ret; - /* LED light */ - ret = anysee_led_ctrl(d, 0x01, 0x03); - if (ret) - return ret; - - /* enable IR */ - ret = anysee_ir_ctrl(d, 1); - if (ret) - return ret; - - return 0; -} - /* I2C */ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) @@ -297,7 +310,7 @@ static struct tda10023_config anysee_tda10023_tda18212_config = { .pll_m = 12, .pll_p = 3, .pll_n = 1, - .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, + .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, .deltaf = 0xba02, }; @@ -309,6 +322,17 @@ static struct tda18212_config anysee_tda18212_config = { .if_dvbc = 5000, }; +static struct tda18212_config anysee_tda18212_config2 = { + .i2c_address = 0x60 /* (0xc0 >> 1) */, + .if_dvbt_6 = 3550, + .if_dvbt_7 = 3700, + .if_dvbt_8 = 4150, + .if_dvbt2_6 = 3250, + .if_dvbt2_7 = 4000, + .if_dvbt2_8 = 4000, + .if_dvbc = 5000, +}; + static struct cx24116_config anysee_cx24116_config = { .demod_address = (0xaa >> 1), .mpg_clk_pos_pol = 0x00, @@ -339,6 +363,11 @@ static struct isl6423_config anysee_isl6423_config = { .addr = (0x10 >> 1), }; +static struct cxd2820r_config anysee_cxd2820r_config = { + .i2c_address = 0x6d, /* (0xda >> 1) */ + .ts_mode = 0x38, +}; + /* * New USB device strings: Mfr=1, Product=2, SerialNumber=0 * Manufacturer: AMT.CO.KR @@ -421,6 +450,14 @@ static struct isl6423_config anysee_isl6423_config = { * IOA[7] TS 1=enabled * IOE[5] STV0903 1=enabled * + * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" + * PCB: 508T2C (rev0.3) + * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff + * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 + * IOA[7] TS 1=enabled + * IOE[5] CXD2820R 1=enabled + * * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" * PCB: 508PTC (rev0.5) * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) @@ -437,7 +474,7 @@ static struct isl6423_config anysee_isl6423_config = { * IOD[6] ZL10353 1=enabled * IOE[0] IF 0=enabled * - * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" * PCB: 508PS2 (rev0.4) * parts: DNBU10512IST(STV0903, STV6110), ISL6423 * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff @@ -446,6 +483,16 @@ static struct isl6423_config anysee_isl6423_config = { * IOE[5] STV0903 1=enabled */ + +/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ +static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + + /* enable / disable tuner access on IOE[4] */ + return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10); +} + static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) { struct dvb_usb_adapter *adap = fe->dvb->priv; @@ -577,7 +624,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* detect hardware only once */ if (adap->fe_adap[0].fe == NULL) { /* Check which hardware we have. - * We must do this call two times to get reliable values (hw bug). + * We must do this call two times to get reliable values + * (hw/fw bug). */ ret = anysee_get_hw_info(adap->dev, hw_info); if (ret) @@ -606,14 +654,14 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) break; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config, - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(mt352_attach, + &anysee_mt352_config, &adap->dev->i2c_adap); if (adap->fe_adap[0].fe) break; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(zl10353_attach, + &anysee_zl10353_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507CD: /* 6 */ @@ -665,8 +713,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, - &adap->dev->i2c_adap); + adap->fe_adap[0].fe = dvb_attach(cx24116_attach, + &anysee_cx24116_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507FA: /* 15 */ @@ -747,17 +795,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) } } + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (tmp == 0xc7) { + if (adap->fe_adap[state->fe_id].fe) + adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + } + break; case ANYSEE_HW_508TC: /* 18 */ case ANYSEE_HW_508PTC: /* 21 */ /* E7 TC */ /* E7 PTC */ - /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); - if (ret) - goto error; - if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { /* disable DVB-T demod on IOD[6] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), @@ -772,7 +822,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach, + adap->fe_adap[state->fe_id].fe = + dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } else { @@ -789,11 +840,19 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach, + adap->fe_adap[state->fe_id].fe = + dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config, &adap->dev->i2c_adap); } + /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ + if (adap->fe_adap[state->fe_id].fe) + adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = + anysee_i2c_gate_ctrl; + + state->has_ci = true; + break; case ANYSEE_HW_508S2: /* 19 */ case ANYSEE_HW_508PS2: /* 22 */ @@ -803,19 +862,41 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (state->fe_id) break; - /* enable transport stream on IOA[7] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); + /* enable DVB-S/S2 demod on IOE[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); if (ret) goto error; - /* enable DVB-S/S2 demod on IOE[5] */ + /* attach demod */ + adap->fe_adap[0].fe = dvb_attach(stv0900_attach, + &anysee_stv0900_config, &adap->dev->i2c_adap, 0); + + state->has_ci = true; + + break; + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* enable DVB-T/T2/C demod on IOE[5] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); if (ret) goto error; - /* attach demod */ - adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, - &adap->dev->i2c_adap, 0); + if (state->fe_id == 0) { + /* DVB-T/T2 */ + adap->fe_adap[state->fe_id].fe = + dvb_attach(cxd2820r_attach, + &anysee_cxd2820r_config, + &adap->dev->i2c_adap, NULL); + } else { + /* DVB-C */ + adap->fe_adap[state->fe_id].fe = + dvb_attach(cxd2820r_attach, + &anysee_cxd2820r_config, + &adap->dev->i2c_adap, adap->fe_adap[0].fe); + } + + state->has_ci = true; break; } @@ -842,24 +923,26 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), - NULL, DVB_PLL_THOMSON_DTT7579); + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); break; case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), - &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + (0xc2 >> 1), &adap->dev->i2c_adap, + DVB_PLL_THOMSON_DTT7579); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1), - &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, + (0xc0 >> 1), &adap->dev->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); break; case ANYSEE_HW_507SI: /* 11 */ @@ -877,22 +960,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* Try first attach TDA18212 silicon tuner on IOE[4], if that * fails attach old simple PLL. */ - /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); - if (ret) - goto error; - /* attach tuner */ fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; - /* disable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10); - if (ret) - goto error; - /* attach tuner */ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe, (0xc0 >> 1), &adap->dev->i2c_adap, @@ -904,11 +977,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 TC */ /* E7 PTC */ - /* enable tuner on IOE[4] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); - if (ret) - goto error; - /* attach tuner */ fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, &adap->dev->i2c_adap, &anysee_tda18212_config); @@ -930,6 +998,15 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) } break; + + case ANYSEE_HW_508T2C: /* 20 */ + /* E7 T2C */ + + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, + &adap->dev->i2c_adap, &anysee_tda18212_config2); + + break; default: fe = NULL; } @@ -939,7 +1016,6 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) else ret = -ENODEV; -error: return ret; } @@ -969,6 +1045,201 @@ static int anysee_rc_query(struct dvb_usb_device *d) return 0; } +static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, + int addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; + u8 val; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); + if (ret) + return ret; + + return val; +} + +static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, + u8 addr, u8 val) +{ + struct dvb_usb_device *d = ci->data; + int ret; + u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; + + ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + struct anysee_state *state = d->priv; + + state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(300); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); + if (ret) + return ret; + + msleep(30); + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) +{ + struct dvb_usb_device *d = ci->data; + int ret; + + ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); + if (ret) + return ret; + + return 0; +} + +static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, + int open) +{ + struct dvb_usb_device *d = ci->data; + struct anysee_state *state = d->priv; + int ret; + u8 tmp; + + ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); + if (ret) + return ret; + + if (tmp == 0) { + ret = DVB_CA_EN50221_POLL_CAM_PRESENT; + if (time_after(jiffies, state->ci_cam_ready)) + ret |= DVB_CA_EN50221_POLL_CAM_READY; + } + + return ret; +} + +static int anysee_ci_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + int ret; + + state->ci.owner = THIS_MODULE; + state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; + state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; + state->ci.read_cam_control = anysee_ci_read_cam_control; + state->ci.write_cam_control = anysee_ci_write_cam_control; + state->ci.slot_reset = anysee_ci_slot_reset; + state->ci.slot_shutdown = anysee_ci_slot_shutdown; + state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; + state->ci.poll_slot_status = anysee_ci_poll_slot_status; + state->ci.data = d; + + ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); + if (ret) + return ret; + + ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); + if (ret) + return ret; + + return 0; +} + +static void anysee_ci_release(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + + /* detach CI */ + if (state->has_ci) + dvb_ca_en50221_release(&state->ci); + + return; +} + +static int anysee_init(struct dvb_usb_device *d) +{ + struct anysee_state *state = d->priv; + int ret; + + /* LED light */ + ret = anysee_led_ctrl(d, 0x01, 0x03); + if (ret) + return ret; + + /* enable IR */ + ret = anysee_ir_ctrl(d, 1); + if (ret) + return ret; + + /* attach CI */ + if (state->has_ci) { + ret = anysee_ci_init(d); + if (ret) { + state->has_ci = false; + return ret; + } + } + + return 0; +} + /* DVB USB Driver stuff */ static struct dvb_usb_device_properties anysee_properties; @@ -1010,6 +1281,16 @@ static int anysee_probe(struct usb_interface *intf, return anysee_init(d); } +static void anysee_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + + anysee_ci_release(d); + dvb_usb_device_exit(intf); + + return; +} + static struct usb_device_id anysee_table[] = { { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, @@ -1029,7 +1310,7 @@ static struct dvb_usb_device_properties anysee_properties = { { .num_frontends = 2, .frontend_ctrl = anysee_frontend_ctrl, - .fe = {{ + .fe = { { .streaming_ctrl = anysee_streaming_ctrl, .frontend_attach = anysee_frontend_attach, .tuner_attach = anysee_tuner_attach, @@ -1057,7 +1338,7 @@ static struct dvb_usb_device_properties anysee_properties = { } } }, - }}, + } }, } }, @@ -1087,7 +1368,7 @@ static struct dvb_usb_device_properties anysee_properties = { static struct usb_driver anysee_driver = { .name = "dvb_usb_anysee", .probe = anysee_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = anysee_disconnect, .id_table = anysee_table, }; diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h index 57ee500b8c0e..8ac879431540 100644 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -36,6 +36,7 @@ #define DVB_USB_LOG_PREFIX "anysee" #include "dvb-usb.h" +#include "dvb_ca_en50221.h" #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) @@ -54,12 +55,16 @@ enum cmd { CMD_GET_IR_CODE = 0x41, CMD_GET_HW_INFO = 0x19, CMD_SMARTCARD = 0x34, + CMD_CI = 0x37, }; struct anysee_state { u8 hw; /* PCB ID */ u8 seq; u8 fe_id:1; /* frondend ID */ + u8 has_ci:1; + struct dvb_ca_en50221 ci; + unsigned long ci_cam_ready; /* jiffies */ }; #define ANYSEE_HW_507T 2 /* E30 */ @@ -69,6 +74,7 @@ struct anysee_state { #define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ #define ANYSEE_HW_508TC 18 /* E7 TC */ #define ANYSEE_HW_508S2 19 /* E7 S2 */ +#define ANYSEE_HW_508T2C 20 /* E7 T2C */ #define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ #define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c index 9cd51ac12076..8a57ed8272de 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-fe.c @@ -40,9 +40,8 @@ * We replace errornous fields by default TPS fields (the ones with value 0). */ -static uint16_t compute_tps(struct dvb_frontend_parameters *p) +static uint16_t compute_tps(struct dtv_frontend_properties *op) { - struct dvb_ofdm_parameters *op = &p->u.ofdm; uint16_t tps = 0; switch (op->code_rate_HP) { @@ -83,7 +82,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p) /* tps |= (0 << 4) */; } - switch (op->constellation) { + switch (op->modulation) { case QAM_16: tps |= (1 << 13); break; @@ -119,7 +118,7 @@ static uint16_t compute_tps(struct dvb_frontend_parameters *p) /* tps |= (0 << 2) */; } - switch (op->hierarchy_information) { + switch (op->hierarchy) { case HIERARCHY_1: tps |= (1 << 10); break; @@ -263,9 +262,9 @@ static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct cinergyt2_fe_state *state = fe->demodulator_priv; struct dvbt_set_parameters_msg param; char result[2]; @@ -274,9 +273,20 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; param.tps = cpu_to_le16(compute_tps(fep)); param.freq = cpu_to_le32(fep->frequency / 1000); - param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; param.flags = 0; + switch (fep->bandwidth_hz) { + case 8000000: + param.bandwidth = 0; + break; + case 7000000: + param.bandwidth = 1; + break; + case 6000000: + param.bandwidth = 2; + break; + } + err = dvb_usb_generic_rw(state->d, (char *)¶m, sizeof(param), result, sizeof(result), 0); @@ -286,12 +296,6 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe, return (err < 0) ? err : 0; } -static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - static void cinergyt2_fe_release(struct dvb_frontend *fe) { struct cinergyt2_fe_state *state = fe->demodulator_priv; @@ -316,9 +320,9 @@ struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) static struct dvb_frontend_ops cinergyt2_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = DRIVER_NAME, - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, @@ -341,7 +345,6 @@ static struct dvb_frontend_ops cinergyt2_fe_ops = { .sleep = cinergyt2_fe_sleep, .set_frontend = cinergyt2_fe_set_frontend, - .get_frontend = cinergyt2_fe_get_frontend, .get_tune_settings = cinergyt2_fe_get_tune_settings, .read_status = cinergyt2_fe_read_status, diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 949ea1bc0aae..3940bb0f9ef6 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -1067,18 +1067,17 @@ static struct dib0070_config dib7070p_dib0070_config = { }; struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *, - struct dvb_frontend_parameters *); + int (*set_param_save) (struct dvb_frontend *); }; -static int dib7070_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib7070_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: offset = 950; break; default: @@ -1087,7 +1086,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index f313182eb9d5..81ef4b46f790 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -30,7 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif "if applicable for the device (default: 0=automatic/off)."); struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); + int (*set_param_save) (struct dvb_frontend *); const struct firmware *frontend_firmware; }; @@ -804,13 +804,14 @@ static struct dib0070_config dib7770p_dib0070_config = { .charge_pump = 2, }; -static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7070_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: offset = 950; break; case BAND_UHF: @@ -818,17 +819,17 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_fronte } deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } -static int dib7770_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib7770_set_param_override(struct dvb_frontend *fe) { - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: dib7000p_set_gpio(fe, 0, 0, 1); @@ -842,7 +843,7 @@ static int dib7770_set_param_override(struct dvb_frontend *fe, } deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) @@ -1205,14 +1206,14 @@ static struct dib0070_config dib807x_dib0070_config[2] = { } }; -static int dib807x_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib807x_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; u16 offset = dib0070_wbd_offset(fe); - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: offset += 750; @@ -1224,7 +1225,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe, deb_info("WBD for DiB8000: %d\n", offset); dib8000_set_wbd_ref(fe, offset); - return state->set_param_save(fe, fep); + return state->set_param_save(fe); } static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) @@ -1279,7 +1280,7 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - 0x80); + 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); @@ -1308,7 +1309,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); @@ -1319,7 +1320,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) { /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); @@ -1328,7 +1329,7 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) } /* STK8096GP */ -struct dibx000_agc_config dib8090_agc_config[2] = { +static struct dibx000_agc_config dib8090_agc_config[2] = { { BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, @@ -1503,22 +1504,22 @@ static struct dib0090_config dib809x_dib0090_config = { .fref_clock_ratio = 6, }; -static int dib8096_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int dib8096_set_param_override(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency/1000); u16 target; int ret = 0; enum frontend_tune_state tune_state = CT_SHUTDOWN; u16 ltgain, rf_gain_limit; - ret = state->set_param_save(fe, fep); + ret = state->set_param_save(fe); if (ret < 0) return ret; - target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; + target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; dib8000_set_wbd_ref(fe, target); @@ -1578,7 +1579,7 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); @@ -1629,7 +1630,7 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0); adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); if (adap->fe_adap[0].fe == NULL) @@ -1641,6 +1642,261 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) return fe_slave == NULL ? -ENODEV : 0; } +/* TFE8096P */ +static struct dibx000_agc_config dib8096p_agc_config[2] = { + { + .band_caps = BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) + | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) + | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 684, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 32767, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 105, + .agc1_slope1 = 0, + .agc1_slope2 = 156, + .agc2_pt1 = 105, + .agc2_pt2 = 255, + .agc2_slope1 = 54, + .agc2_slope2 = 0, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, + } , { + .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, + P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, + P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, + P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) + | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) + | (0 << 4) | (5 << 1) | (0 << 0), + + .inv_gain = 732, + .time_stabiliz = 10, + + .alpha_level = 0, + .thlock = 118, + + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, + + .agc1_max = 65535, + .agc1_min = 0, + + .agc2_max = 32767, + .agc2_min = 0, + + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 98, + .agc1_slope1 = 0, + .agc1_slope2 = 167, + .agc2_pt1 = 98, + .agc2_pt2 = 255, + .agc2_slope1 = 52, + .agc2_slope2 = 0, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, + } +}; + +static struct dibx000_bandwidth_config dib8096p_clock_config_12_mhz = { + 108000, 13500, + 1, 9, 1, 0, 0, + 0, 0, 0, 0, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20199729, + 12000000, +}; + +static struct dib8000_config tfe8096p_dib8000_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib8096p_agc_config, + .pll = &dib8096p_clock_config_12_mhz, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .agc_control = NULL, + .diversity_delay = 48, + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static struct dib0090_wbd_slope dib8096p_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 860, 51, 866, 21, 375, 4}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static const struct dib0090_config tfe8096p_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib8096p_tuner_sleep, + .sleep = dib8096p_tuner_sleep, + + .freq_offset_khz_uhf = -143, + .freq_offset_khz_vhf = -143, + + .get_adc_power = dib8090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 1, + + .wbd = dib8096p_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 0, +}; + +struct dibx090p_adc { + u32 freq; /* RF freq MHz */ + u32 timf; /* New Timf */ + u32 pll_loopdiv; /* New prediv */ + u32 pll_prediv; /* New loopdiv */ +}; + +struct dibx090p_adc dib8090p_adc_tab[] = { + { 50000, 17043521, 16, 3}, /* 64 MHz */ + {878000, 20199729, 9, 1}, /* 60 MHz */ + {0xffffffff, 0, 0, 0}, /* 60 MHz */ +}; + +static int dib8096p_agc_startup(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + struct dibx000_bandwidth_config pll; + u16 target; + int better_sampling_freq = 0, ret; + struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0]; + + ret = state->set_param_save(fe); + if (ret < 0) + return ret; + memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); + + dib0090_pwm_gain_reset(fe); + /* dib0090_get_wbd_target is returning any possible + temperature compensated wbd-target */ + target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + + + while (p->frequency / 1000 > adc_table->freq) { + better_sampling_freq = 1; + adc_table++; + } + + if ((adc_table->freq != 0xffffffff) && better_sampling_freq) { + pll.pll_ratio = adc_table->pll_loopdiv; + pll.pll_prediv = adc_table->pll_prediv; + dib8000_update_pll(fe, &pll); + dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf); + } + return 0; +} + +static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1); + + adap->fe_adap[0].fe = dvb_attach(dib8000_attach, + &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe8096p_dib0090_config) == NULL) + return -ENODEV; + + dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup; + return 0; +} + /* STK9090M */ static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { @@ -1883,7 +2139,7 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 2000); + dib0700_set_i2c_speed(adap->dev, 1500); if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) return -ENODEV; release_firmware(state->frontend_firmware); @@ -1962,7 +2218,8 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; - dib0700_set_i2c_speed(adap->dev, 2000); + + dib0700_set_i2c_speed(adap->dev, 1500); if (dib9000_firmware_post_pll_init(adap->fe_adap[0].fe) < 0) return -ENODEV; @@ -1975,7 +2232,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) return -ENODEV; fe_slave->dvb = adap->fe_adap[0].fe->dvb; - dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 2000); + dib9000_fw_set_component_bus_speed(adap->fe_adap[0].fe, 1500); if (dib9000_firmware_post_pll_init(fe_slave) < 0) return -ENODEV; } @@ -2064,7 +2321,7 @@ static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_ return 0; } -static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7090_agc_startup(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; @@ -2073,13 +2330,13 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para struct dib7090p_best_adc adc; int ret; - ret = state->set_param_save(fe, fep); + ret = state->set_param_save(fe); if (ret < 0) return ret; memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); dib0090_pwm_gain_reset(fe); - target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2; + target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; dib7000p_set_wbd_ref(fe, target); if (dib7090p_get_best_sampling(fe, &adc) == 0) { @@ -2092,6 +2349,49 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para return 0; } +static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + deb_info("AGC restart callback: %d", restart); + if (restart == 0) /* before AGC startup */ + dib0090_set_dc_servo(fe, 1); + return 0; +} + +static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global) +{ + u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1; + s16 wbd_delta; + + if ((fe->dtv_property_cache.frequency) < 400000000) + threshold_agc1 = 25000; + else + threshold_agc1 = 30000; + + wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2; + wbd_offset = dib0090_get_wbd_offset(fe); + dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd); + wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ; + + deb_info("update lna, agc_global=%d agc1=%d agc2=%d", + agc_global, agc1, agc2); + deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d", + wbd, wbd_target, wbd_offset, wbd_delta); + + if ((agc1 < threshold_agc1) && (wbd_delta > 0)) { + dib0090_set_switch(fe, 1, 1, 1); + dib0090_set_vga(fe, 0); + dib0090_update_rframp_7090(fe, 0); + dib0090_update_tuning_table_7090(fe, 0); + } else { + dib0090_set_vga(fe, 1); + dib0090_update_rframp_7090(fe, 1); + dib0090_update_tuning_table_7090(fe, 1); + dib0090_set_switch(fe, 0, 0, 0); + } + + return 0; +} + static struct dib0090_wbd_slope dib7090_wbd_table[] = { { 380, 81, 850, 64, 540, 4}, { 860, 51, 866, 21, 375, 4}, @@ -2100,7 +2400,16 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = { { 0xFFFF, 0, 0, 0, 0, 0}, }; -struct dibx000_agc_config dib7090_agc_config[2] = { +static struct dib0090_wbd_slope dib7090e_wbd_table[] = { + { 380, 81, 850, 64, 540, 4}, + { 700, 51, 866, 21, 320, 4}, + { 860, 48, 666, 18, 330, 6}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, +}; + +static struct dibx000_agc_config dib7090_agc_config[2] = { { .band_caps = BAND_UHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, @@ -2278,6 +2587,34 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { } }; +static struct dib7000p_config tfe7090e_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = dib7090e_update_lna, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + static const struct dib0090_config nim7090_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, @@ -2312,6 +2649,107 @@ static const struct dib0090_config nim7090_dib0090_config = { .in_soc = 1, }; +static const struct dib0090_config tfe7090e_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090e_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 1, + .is_dib7090e = 1, +}; + +static struct dib7000p_config tfe7790e_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = dib7090e_update_lna, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .enMpegOutput = 1, +}; + +static const struct dib0090_config tfe7790e_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090e_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + .force_cband_input = 1, + .is_dib7090e = 1, + .force_crystal_mode = 1, +}; + static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { { .io.clock_khz = 12000, @@ -2504,6 +2942,97 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) return 0; } +static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(20); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + 1, 0x10, &tfe7090e_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80, &tfe7090e_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_state *st = adap->dev->priv; + + /* The TFE7790E requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(20); + dib0700_ctrl_clock(adap->dev, 72, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(20); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + 1, 0x10, &tfe7790e_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + __func__); + return -ENODEV; + } + adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + 0x80, &tfe7790e_dib7000p_config); + + return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; +} + +static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe7790e_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + + if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, + &tfe7090e_dib0090_config) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + /* STK7070PD */ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { { @@ -2960,6 +3489,9 @@ struct usb_device_id dib0700_usb_id_table[] = { /* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) }, +/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -4025,6 +4557,127 @@ struct dvb_usb_device_properties dib0700_devices[] = { RC_TYPE_NEC, .change_protocol = dib0700_change_protocol, }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090e_frontend_attach, + .tuner_attach = tfe7090e_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7090E reference design", + { &dib0700_usb_id_table[78], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7790e_frontend_attach, + .tuner_attach = tfe7790e_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7790E reference design", + { &dib0700_usb_id_table[79], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = tfe8096p_frontend_attach, + .tuner_attach = tfe8096p_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + } }, + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE8096P reference design", + { &dib0700_usb_id_table[80], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, }, }; diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 0a9a79820f26..ff34419a4c88 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -118,12 +118,12 @@ static struct mt352_config digitv_mt352_config = { .demod_init = digitv_mt352_demod_init, }; -static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; u8 b[5]; - fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b)); + fe->ops.tuner_ops.calc_regs(fe, b, sizeof(b)); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index 17413adec7a1..3d81daa49172 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -16,7 +16,7 @@ struct dtt200u_fe_state { fe_status_t stat; - struct dvb_frontend_parameters fep; + struct dtv_frontend_properties fep; struct dvb_frontend frontend; }; @@ -100,22 +100,27 @@ static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron return 0; } -static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dtt200u_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dtt200u_fe_state *state = fe->demodulator_priv; int i; fe_status_t st; u16 freq = fep->frequency / 250000; u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 }; - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break; - case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break; - case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break; - case BANDWIDTH_AUTO: return -EOPNOTSUPP; - default: - return -EINVAL; + switch (fep->bandwidth_hz) { + case 8000000: + bwbuf[1] = 8; + break; + case 7000000: + bwbuf[1] = 7; + break; + case 6000000: + bwbuf[1] = 6; + break; + default: + return -EINVAL; } dvb_usb_generic_write(state->d,bwbuf,2); @@ -134,11 +139,11 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe, return 0; } -static int dtt200u_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dtt200u_fe_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dtt200u_fe_state *state = fe->demodulator_priv; - memcpy(fep,&state->fep,sizeof(struct dvb_frontend_parameters)); + memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties)); return 0; } @@ -172,9 +177,9 @@ error: } static struct dvb_frontend_ops dtt200u_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "WideView USB DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 250000, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index ba4a7517354f..ddf282f355b3 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -141,11 +141,17 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) goto err_dmx_dev; } - dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx); + if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, + &adap->demux.dmx)) < 0) { + err("dvb_net_init failed: error %d",ret); + goto err_net_init; + } adap->state |= DVB_USB_ADAP_STATE_DVB; return 0; +err_net_init: + dvb_dmxdev_release(&adap->dmxdev); err_dmx_dev: dvb_dmx_release(&adap->demux); err_dmx: diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2d08c9b5128a..d390ddaa5a53 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -109,10 +109,13 @@ #define USB_PID_DIBCOM_STK807XPVR 0x1f98 #define USB_PID_DIBCOM_STK8096GP 0x1fa0 #define USB_PID_DIBCOM_NIM8096MD 0x1fa8 +#define USB_PID_DIBCOM_TFE8096P 0x1f9C #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DIBCOM_STK7770P 0x1e80 #define USB_PID_DIBCOM_NIM7090 0x1bb2 #define USB_PID_DIBCOM_TFE7090PVR 0x1bb4 +#define USB_PID_DIBCOM_TFE7090E 0x1bb7 +#define USB_PID_DIBCOM_TFE7790E 0x1e6e #define USB_PID_DIBCOM_NIM9090M 0x2383 #define USB_PID_DIBCOM_NIM9090MD 0x2384 #define USB_PID_DPOSH_M9206_COLD 0x9206 @@ -128,6 +131,8 @@ #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 #define USB_PID_INTEL_CE9500 0x9500 #define USB_PID_ITETECH_IT9135 0x9135 +#define USB_PID_ITETECH_IT9135_9005 0x9005 +#define USB_PID_ITETECH_IT9135_9006 0x9006 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_399U_2 0xe400 #define USB_PID_KWORLD_395U 0xe396 @@ -322,6 +327,7 @@ #define USB_PID_TVWAY_PLUS 0x0002 #define USB_PID_SVEON_STV20 0xe39d #define USB_PID_SVEON_STV22 0xe401 +#define USB_PID_SVEON_STV22_IT9137 0xe411 #define USB_PID_AZUREWAVE_AZ6027 0x3275 #define USB_PID_TERRATEC_DVBS2CI_V1 0x10a4 #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index ff941d20e6b7..451c5a7adfb2 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1435,22 +1435,40 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +enum dw2102_table_entry { + CYPRESS_DW2102, + CYPRESS_DW2101, + CYPRESS_DW2104, + TEVII_S650, + TERRATEC_CINERGY_S, + CYPRESS_DW3101, + TEVII_S630, + PROF_1100, + TEVII_S660, + PROF_7500, + GENIATECH_SU3000, + TERRATEC_CINERGY_S2, + TEVII_S480_1, + TEVII_S480_2, + X3M_SPC1400HD, +}; + static struct usb_device_id dw2102_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, - {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, - {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, - {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, - {USB_DEVICE(0x3034, 0x7500)}, - {USB_DEVICE(0x1f4d, 0x3000)}, - {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, - {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, - {USB_DEVICE(0x1f4d, 0x3100)}, + [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, + [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, + [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, + [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, + [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, + [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, + [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, + [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, + [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, + [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)}, + [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)}, + [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, + [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, + [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, + [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, { } }; @@ -1610,15 +1628,15 @@ static struct dvb_usb_device_properties dw2102_properties = { .num_device_descs = 3, .devices = { {"DVBWorld DVB-S 2102 USB2.0", - {&dw2102_table[0], NULL}, + {&dw2102_table[CYPRESS_DW2102], NULL}, {NULL}, }, {"DVBWorld DVB-S 2101 USB2.0", - {&dw2102_table[1], NULL}, + {&dw2102_table[CYPRESS_DW2101], NULL}, {NULL}, }, {"TerraTec Cinergy S USB", - {&dw2102_table[4], NULL}, + {&dw2102_table[TERRATEC_CINERGY_S], NULL}, {NULL}, }, } @@ -1664,11 +1682,11 @@ static struct dvb_usb_device_properties dw2104_properties = { .num_device_descs = 2, .devices = { { "DVBWorld DW2104 USB2.0", - {&dw2102_table[2], NULL}, + {&dw2102_table[CYPRESS_DW2104], NULL}, {NULL}, }, { "TeVii S650 USB2.0", - {&dw2102_table[3], NULL}, + {&dw2102_table[TEVII_S650], NULL}, {NULL}, }, } @@ -1715,7 +1733,7 @@ static struct dvb_usb_device_properties dw3101_properties = { .num_device_descs = 1, .devices = { { "DVBWorld DVB-C 3101 USB2.0", - {&dw2102_table[5], NULL}, + {&dw2102_table[CYPRESS_DW3101], NULL}, {NULL}, }, } @@ -1761,7 +1779,7 @@ static struct dvb_usb_device_properties s6x0_properties = { .num_device_descs = 1, .devices = { {"TeVii S630 USB", - {&dw2102_table[6], NULL}, + {&dw2102_table[TEVII_S630], NULL}, {NULL}, }, } @@ -1770,33 +1788,33 @@ static struct dvb_usb_device_properties s6x0_properties = { struct dvb_usb_device_properties *p1100; static struct dvb_usb_device_description d1100 = { "Prof 1100 USB ", - {&dw2102_table[7], NULL}, + {&dw2102_table[PROF_1100], NULL}, {NULL}, }; struct dvb_usb_device_properties *s660; static struct dvb_usb_device_description d660 = { "TeVii S660 USB", - {&dw2102_table[8], NULL}, + {&dw2102_table[TEVII_S660], NULL}, {NULL}, }; static struct dvb_usb_device_description d480_1 = { "TeVii S480.1 USB", - {&dw2102_table[12], NULL}, + {&dw2102_table[TEVII_S480_1], NULL}, {NULL}, }; static struct dvb_usb_device_description d480_2 = { "TeVii S480.2 USB", - {&dw2102_table[13], NULL}, + {&dw2102_table[TEVII_S480_2], NULL}, {NULL}, }; struct dvb_usb_device_properties *p7500; static struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", - {&dw2102_table[9], NULL}, + {&dw2102_table[PROF_7500], NULL}, {NULL}, }; @@ -1842,15 +1860,15 @@ static struct dvb_usb_device_properties su3000_properties = { .num_device_descs = 3, .devices = { { "SU3000HD DVB-S USB2.0", - { &dw2102_table[10], NULL }, + { &dw2102_table[GENIATECH_SU3000], NULL }, { NULL }, }, { "Terratec Cinergy S2 USB HD", - { &dw2102_table[11], NULL }, + { &dw2102_table[TERRATEC_CINERGY_S2], NULL }, { NULL }, }, { "X3M TV SPC1400HD PCI", - { &dw2102_table[14], NULL }, + { &dw2102_table[X3M_SPC1400HD], NULL }, { NULL }, }, } @@ -1859,12 +1877,11 @@ static struct dvb_usb_device_properties su3000_properties = { static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { - p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + p1100 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p1100) return -ENOMEM; /* copy default structure */ - memcpy(p1100, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); /* fill only different fields */ p1100->firmware = "dvb-usb-p1100.fw"; p1100->devices[0] = d1100; @@ -1872,13 +1889,12 @@ static int dw2102_probe(struct usb_interface *intf, p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; - s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + s660 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!s660) { kfree(p1100); return -ENOMEM; } - memcpy(s660, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); s660->firmware = "dvb-usb-s660.fw"; s660->num_device_descs = 3; s660->devices[0] = d660; @@ -1886,14 +1902,13 @@ static int dw2102_probe(struct usb_interface *intf, s660->devices[2] = d480_2; s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach; - p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + p7500 = kmemdup(&s6x0_properties, + sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p7500) { kfree(p1100); kfree(s660); return -ENOMEM; } - memcpy(p7500, &s6x0_properties, - sizeof(struct dvb_usb_device_properties)); p7500->firmware = "dvb-usb-p7500.fw"; p7500->devices[0] = d7500; p7500->rc.legacy.rc_map_table = rc_map_tbs_table; diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c index 015b4e8af1a5..90a70c66a96e 100644 --- a/drivers/media/dvb/dvb-usb/friio-fe.c +++ b/drivers/media/dvb/dvb-usb/friio-fe.c @@ -282,23 +282,24 @@ static int jdvbt90502_set_property(struct dvb_frontend *fe, return r; } -static int jdvbt90502_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int jdvbt90502_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; p->inversion = INVERSION_AUTO; - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - p->u.ofdm.code_rate_HP = FEC_AUTO; - p->u.ofdm.code_rate_LP = FEC_AUTO; - p->u.ofdm.constellation = QAM_64; - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; + p->bandwidth_hz = 6000000; + p->code_rate_HP = FEC_AUTO; + p->code_rate_LP = FEC_AUTO; + p->modulation = QAM_64; + p->transmission_mode = TRANSMISSION_MODE_AUTO; + p->guard_interval = GUARD_INTERVAL_AUTO; + p->hierarchy = HIERARCHY_AUTO; return 0; } -static int jdvbt90502_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int jdvbt90502_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + /** * NOTE: ignore all the parameters except frequency. * others should be fixed to the proper value for ISDB-T, @@ -438,14 +439,12 @@ error: } static struct dvb_frontend_ops jdvbt90502_ops = { - + .delsys = { SYS_ISDBT }, .info = { .name = "Comtech JDVBT90502 ISDB-T", - .type = FE_OFDM, .frequency_min = 473000000, /* UHF 13ch, center */ .frequency_max = 767142857, /* UHF 62ch, center */ - .frequency_stepsize = JDVBT90502_PLL_CLK / - JDVBT90502_PLL_DIVIDER, + .frequency_stepsize = JDVBT90502_PLL_CLK / JDVBT90502_PLL_DIVIDER, .frequency_tolerance = 0, /* NOTE: this driver ignores all parameters but frequency. */ diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 5426267980c7..67957dd99ede 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -113,28 +113,12 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } -static int gp8psk_fe_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - deb_fe("%s(..)\n", __func__); - return 0; -} - -static int gp8psk_fe_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - deb_fe("%s(..)\n", __func__); - return 0; -} - - -static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) { struct gp8psk_fe_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 cmd[10]; - u32 freq = fep->frequency * 1000; + u32 freq = c->frequency * 1000; int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); deb_fe("%s()\n", __func__); @@ -342,9 +326,9 @@ success: static struct dvb_frontend_ops gp8psk_fe_ops = { + .delsys = { SYS_DVBS }, .info = { .name = "Genpix DVB-S", - .type = FE_QPSK, .frequency_min = 800000, .frequency_max = 2250000, .frequency_stepsize = 100, @@ -366,8 +350,6 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .init = NULL, .sleep = NULL, - .set_property = gp8psk_fe_set_property, - .get_property = gp8psk_fe_get_property, .set_frontend = gp8psk_fe_set_frontend, .get_tune_settings = gp8psk_fe_get_tune_settings, diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 67094b879bb4..9f01cd7a6e3f 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -52,42 +52,59 @@ static int pid_filter; module_param_named(pid, pid_filter, int, 0644); MODULE_PARM_DESC(pid, "set default 0=on 1=off"); +static int dvb_usb_it913x_firmware; +module_param_named(firmware, dvb_usb_it913x_firmware, int, 0644); +MODULE_PARM_DESC(firmware, "set firmware 0=auto 1=IT9137 2=IT9135V1"); + + int cmd_counter; DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct it913x_state { u8 id; -}; - -struct ite_config { - u8 chip_ver; - u16 chip_type; - u32 firmware; - u8 tuner_id_0; - u8 tuner_id_1; - u8 dual_mode; + struct ite_config it913x_config; }; struct ite_config it913x_config; +#define IT913X_RETRY 10 +#define IT913X_SND_TIMEOUT 100 +#define IT913X_RCV_TIMEOUT 200 + static int it913x_bulk_write(struct usb_device *dev, u8 *snd, int len, u8 pipe) { - int ret, actual_l; + int ret, actual_l, i; + + for (i = 0; i < IT913X_RETRY; i++) { + ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len , &actual_l, IT913X_SND_TIMEOUT); + if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT) + break; + } + + if (len != actual_l && ret == 0) + ret = -EAGAIN; - ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 100); return ret; } static int it913x_bulk_read(struct usb_device *dev, u8 *rev, int len, u8 pipe) { - int ret, actual_l; + int ret, actual_l, i; + + for (i = 0; i < IT913X_RETRY; i++) { + ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len , &actual_l, IT913X_RCV_TIMEOUT); + if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT) + break; + } + + if (len != actual_l && ret == 0) + ret = -EAGAIN; - ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 200); return ret; } @@ -100,7 +117,7 @@ static u16 check_sum(u8 *p, u8 len) return ~sum; } -static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, +static int it913x_usb_talk(struct usb_device *udev, u8 mode, u8 pro, u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) { int ret = 0, i, buf_size = 1; @@ -159,22 +176,41 @@ static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, buff[buf_size++] = (chk_sum & 0xff); ret = it913x_bulk_write(udev, buff, buf_size , 0x02); + if (ret < 0) + goto error; - ret |= it913x_bulk_read(udev, buff, (mode & 1) ? + ret = it913x_bulk_read(udev, buff, (mode & 1) ? 5 : len + 5 , 0x01); + if (ret < 0) + goto error; rlen = (mode & 0x1) ? 0x1 : len; if (mode & 1) - ret |= buff[2]; + ret = buff[2]; else memcpy(data, &buff[3], rlen); cmd_counter++; - kfree(buff); +error: kfree(buff); - return (ret < 0) ? -ENODEV : 0; + return ret; +} + +static int it913x_io(struct usb_device *udev, u8 mode, u8 pro, + u8 cmd, u32 reg, u8 addr, u8 *data, u8 len) +{ + int ret, i; + + for (i = 0; i < IT913X_RETRY; i++) { + ret = it913x_usb_talk(udev, mode, pro, + cmd, reg, addr, data, len); + if (ret != -EAGAIN) + break; + } + + return ret; } static int it913x_wr_reg(struct usb_device *udev, u8 pro, u32 reg , u8 data) @@ -223,15 +259,15 @@ static u32 it913x_query(struct usb_device *udev, u8 pro) static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - int ret = 0; + struct usb_device *udev = adap->dev->udev; + int ret; u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) return -EAGAIN; deb_info(1, "PID_C (%02x)", onoff); - if (!onoff) - ret = it913x_wr_reg(adap->dev->udev, pro, PID_RST, 0x1); + ret = it913x_wr_reg(udev, pro, PID_EN, onoff); mutex_unlock(&adap->dev->i2c_mutex); return ret; @@ -241,27 +277,20 @@ static int it913x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff) { struct usb_device *udev = adap->dev->udev; - int ret = 0; + int ret; u8 pro = (adap->id == 0) ? DEV_0_DMOD : DEV_1_DMOD; - if (pid_filter > 0) - return 0; - if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) return -EAGAIN; deb_info(1, "PID_F (%02x)", onoff); - if (onoff) { - ret = it913x_wr_reg(udev, pro, PID_EN, 0x1); - - ret |= it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); - ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8)); + ret = it913x_wr_reg(udev, pro, PID_LSB, (u8)(pid & 0xff)); - ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff); + ret |= it913x_wr_reg(udev, pro, PID_MSB, (u8)(pid >> 8)); - ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); + ret |= it913x_wr_reg(udev, pro, PID_INX_EN, (u8)onoff); - } + ret |= it913x_wr_reg(udev, pro, PID_INX, (u8)(index & 0x1f)); mutex_unlock(&adap->dev->i2c_mutex); return 0; @@ -337,15 +366,73 @@ static int it913x_rc_query(struct dvb_usb_device *d) if ((ibuf[2] + ibuf[3]) == 0xff) { key = ibuf[2]; - key += ibuf[0] << 8; - deb_info(1, "INT Key =%08x", key); + key += ibuf[0] << 16; + key += ibuf[1] << 8; + deb_info(1, "NEC Extended Key =%08x", key); if (d->rc_dev != NULL) rc_keydown(d->rc_dev, key, 0); } + mutex_unlock(&d->i2c_mutex); return ret; } + +/* Firmware sets raw */ +const char fw_it9135_v1[] = "dvb-usb-it9135-01.fw"; +const char fw_it9135_v2[] = "dvb-usb-it9135-02.fw"; +const char fw_it9137[] = "dvb-usb-it9137-01.fw"; + +static int ite_firmware_select(struct usb_device *udev, + struct dvb_usb_device_properties *props) +{ + int sw; + /* auto switch */ + if (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_ITETECH_IT9135) + sw = IT9135_V1_FW; + else if (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_ITETECH_IT9135_9005) + sw = IT9135_V1_FW; + else if (le16_to_cpu(udev->descriptor.idProduct) == + USB_PID_ITETECH_IT9135_9006) { + sw = IT9135_V2_FW; + if (it913x_config.tuner_id_0 == 0) + it913x_config.tuner_id_0 = IT9135_60; + } else + sw = IT9137_FW; + + /* force switch */ + if (dvb_usb_it913x_firmware != IT9135_AUTO) + sw = dvb_usb_it913x_firmware; + + switch (sw) { + case IT9135_V1_FW: + it913x_config.firmware_ver = 1; + it913x_config.adc_x2 = 1; + props->firmware = fw_it9135_v1; + break; + case IT9135_V2_FW: + it913x_config.firmware_ver = 1; + it913x_config.adc_x2 = 1; + props->firmware = fw_it9135_v2; + break; + case IT9137_FW: + default: + it913x_config.firmware_ver = 0; + it913x_config.adc_x2 = 0; + props->firmware = fw_it9137; + } + + return 0; +} + +#define TS_MPEG_PKT_SIZE 188 +#define EP_LOW 21 +#define TS_BUFFER_SIZE_PID (EP_LOW*TS_MPEG_PKT_SIZE) +#define EP_HIGH 348 +#define TS_BUFFER_SIZE_MAX (EP_HIGH*TS_MPEG_PKT_SIZE) + static int it913x_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, @@ -359,6 +446,19 @@ static int it913x_identify_state(struct usb_device *udev, /* checnk for dual mode */ it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); + if (udev->speed != USB_SPEED_HIGH) { + props->adapter[0].fe[0].pid_filter_count = 5; + info("USB 1 low speed mode - connect to USB 2 port"); + if (pid_filter > 0) + pid_filter = 0; + if (it913x_config.dual_mode) { + it913x_config.dual_mode = 0; + info("Dual mode not supported in USB 1"); + } + } else /* For replugging */ + if(props->adapter[0].fe[0].pid_filter_count == 5) + props->adapter[0].fe[0].pid_filter_count = 31; + /* TODO different remotes */ remote = it913x_read_reg(udev, 0x49ac); /* Remote */ if (remote == 0) @@ -370,6 +470,28 @@ static int it913x_identify_state(struct usb_device *udev, info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode , remote, it913x_config.tuner_id_0); + /* Select Stream Buffer Size and pid filter option*/ + if (pid_filter) { + props->adapter[0].fe[0].stream.u.bulk.buffersize = + TS_BUFFER_SIZE_MAX; + props->adapter[0].fe[0].caps &= + ~DVB_USB_ADAP_NEED_PID_FILTERING; + } else + props->adapter[0].fe[0].stream.u.bulk.buffersize = + TS_BUFFER_SIZE_PID; + + if (it913x_config.dual_mode) { + props->adapter[1].fe[0].stream.u.bulk.buffersize = + props->adapter[0].fe[0].stream.u.bulk.buffersize; + props->num_adapters = 2; + if (pid_filter) + props->adapter[1].fe[0].caps = + props->adapter[0].fe[0].caps; + } else + props->num_adapters = 1; + + ret = ite_firmware_select(udev, props); + if (firm_no > 0) { *cold = 0; return 0; @@ -391,18 +513,22 @@ static int it913x_identify_state(struct usb_device *udev, ret = it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); } - props->num_adapters = 2; - } else - props->num_adapters = 1; + } reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); if (it913x_config.dual_mode) { ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); - ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); + if (it913x_config.firmware_ver == 1) + ret |= it913x_wr_reg(udev, DEV_0, 0xcfff, 0x1); + else + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); } else { ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0); - ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); + if (it913x_config.firmware_ver == 1) + ret |= it913x_wr_reg(udev, DEV_0, 0xcfff, 0x0); + else + ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); } *cold = 1; @@ -428,35 +554,45 @@ static int it913x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } - static int it913x_download_firmware(struct usb_device *udev, const struct firmware *fw) { - int ret = 0, i; - u8 packet_size, dlen; + int ret = 0, i = 0, pos = 0; + u8 packet_size, min_pkt; u8 *fw_data; - packet_size = 0x29; - ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); info("FRM Starting Firmware Download"); - /* This uses scatter write firmware headers follow */ - /* 03 XX 00 XX = chip number? */ - - for (i = 0; i < fw->size; i += packet_size) { - if (i > 0) - packet_size = 0x39; - fw_data = (u8 *)(fw->data + i); - dlen = ((i + packet_size) > fw->size) - ? (fw->size - i) : packet_size; - ret |= it913x_io(udev, WRITE_DATA, DEV_0, - CMD_SCATTER_WRITE, 0, 0, fw_data, dlen); - udelay(1000); + + /* Multi firmware loader */ + /* This uses scatter write firmware headers */ + /* The firmware must start with 03 XX 00 */ + /* and be the extact firmware length */ + + if (it913x_config.chip_ver == 2) + min_pkt = 0x11; + else + min_pkt = 0x19; + + while (i <= fw->size) { + if (((fw->data[i] == 0x3) && (fw->data[i + 2] == 0x0)) + || (i == fw->size)) { + packet_size = i - pos; + if ((packet_size > min_pkt) || (i == fw->size)) { + fw_data = (u8 *)(fw->data + pos); + pos += packet_size; + if (packet_size > 0) + ret |= it913x_io(udev, WRITE_DATA, + DEV_0, CMD_SCATTER_WRITE, 0, + 0, fw_data, packet_size); + udelay(1000); + } + } + i++; } - ret |= it913x_io(udev, WRITE_CMD, DEV_0, - CMD_BOOT, 0, 0, NULL, 0); + ret |= it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); msleep(100); @@ -474,12 +610,17 @@ static int it913x_download_firmware(struct usb_device *udev, /* Tuner function */ if (it913x_config.dual_mode) ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); - - ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); - ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); - if (it913x_config.dual_mode) { - ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); - ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); + else + ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0x68); + + if ((it913x_config.chip_ver == 1) && + (it913x_config.chip_type == 0x9135)) { + ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); + ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); + if (it913x_config.dual_mode) { + ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); + ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); + } } return (ret < 0) ? -ENODEV : 0; @@ -500,32 +641,23 @@ static int it913x_name(struct dvb_usb_adapter *adap) static int it913x_frontend_attach(struct dvb_usb_adapter *adap) { struct usb_device *udev = adap->dev->udev; + struct it913x_state *st = adap->dev->priv; int ret = 0; - u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); - u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; - u8 tuner_id, tuner_type; + u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize / 4; + u8 pkt_size = 0x80; + + if (adap->dev->udev->speed != USB_SPEED_HIGH) + pkt_size = 0x10; + + it913x_config.adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); if (adap->id == 0) - tuner_id = it913x_config.tuner_id_0; - else - tuner_id = it913x_config.tuner_id_1; - - /* TODO we always use IT9137 possible references here*/ - /* Documentation suggests don't care */ - switch (tuner_id) { - case 0x51: - case 0x52: - case 0x60: - case 0x61: - case 0x62: - default: - case 0x38: - tuner_type = IT9137; - } + memcpy(&st->it913x_config, &it913x_config, + sizeof(struct ite_config)); adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, - &adap->dev->i2c_adap, adap_addr, adf, tuner_type); + &adap->dev->i2c_adap, adap_addr, &st->it913x_config); if (adap->id == 0 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); @@ -536,13 +668,13 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_LSB, ep_size & 0xff); ret = it913x_wr_reg(udev, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); - ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, 0x80); + ret = it913x_wr_reg(udev, DEV_0, EP4_MAX_PKT, pkt_size); } else if (adap->id == 1 && adap->fe_adap[0].fe) { ret = it913x_wr_reg(udev, DEV_0, EP0_TX_EN, 0x6f); ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_LSB, ep_size & 0xff); ret = it913x_wr_reg(udev, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); - ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, 0x80); + ret = it913x_wr_reg(udev, DEV_0, EP5_MAX_PKT, pkt_size); ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2IF2_EN, 0x1); ret = it913x_wr_reg(udev, DEV_1_DMOD, MP2IF_SERIAL, 0x1); ret = it913x_wr_reg(udev, DEV_1, TOP_HOSTB_SER_MODE, 0x1); @@ -582,6 +714,9 @@ static int it913x_probe(struct usb_interface *intf, static struct usb_device_id it913x_table[] = { { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) }, + { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22_IT9137) }, + { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9005) }, + { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135_9006) }, {} /* Terminating entry */ }; @@ -614,8 +749,8 @@ static struct dvb_usb_device_properties it913x_properties = { .endpoint = 0x04, .u = {/* Keep Low if PID filter on */ .bulk = { - .buffersize = 3584, - + .buffersize = + TS_BUFFER_SIZE_PID, } } } @@ -639,8 +774,8 @@ static struct dvb_usb_device_properties it913x_properties = { .endpoint = 0x05, .u = { .bulk = { - .buffersize = 3584, - + .buffersize = + TS_BUFFER_SIZE_PID, } } } @@ -654,10 +789,10 @@ static struct dvb_usb_device_properties it913x_properties = { .rc_query = it913x_rc_query, .rc_interval = IT913X_POLL, .allowed_protos = RC_TYPE_NEC, - .rc_codes = RC_MAP_KWORLD_315U, + .rc_codes = RC_MAP_MSI_DIGIVOX_III, }, .i2c_algo = &it913x_i2c_algo, - .num_device_descs = 2, + .num_device_descs = 5, .devices = { { "Kworld UB499-2T T09(IT9137)", { &it913x_table[0], NULL }, @@ -665,6 +800,15 @@ static struct dvb_usb_device_properties it913x_properties = { { "ITE 9135 Generic", { &it913x_table[1], NULL }, }, + { "Sveon STV22 Dual DVB-T HDTV(IT9137)", + { &it913x_table[2], NULL }, + }, + { "ITE 9135(9005) Generic", + { &it913x_table[3], NULL }, + }, + { "ITE 9135(9006) Generic", + { &it913x_table[4], NULL }, + }, } }; @@ -679,5 +823,5 @@ module_usb_driver(it913x_driver); MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.07"); +MODULE_VERSION("1.22"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 1a876a65ed56..b3fe05bbffc9 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -388,8 +388,7 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__, pid, index, onoff); - if (onoff) - if (!pid_filter) { + if (onoff) { ret = mutex_lock_interruptible(&adap->dev->i2c_mutex); if (ret < 0) return -EAGAIN; @@ -654,6 +653,9 @@ static int lme2510_identify_state(struct usb_device *udev, struct dvb_usb_device_description **desc, int *cold) { + if (pid_filter > 0) + props->adapter[0].fe[0].caps &= + ~DVB_USB_ADAP_NEED_PID_FILTERING; *cold = 0; return 0; } @@ -1293,5 +1295,5 @@ module_usb_driver(lme2510_driver); MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("1.90"); +MODULE_VERSION("1.91"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c index d1f58371c711..d83df4bb72d3 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c @@ -102,8 +102,8 @@ fail: } static -int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, - fe_modulation_t *constellation) +int mxl1x1sf_demod_get_tps_modulation(struct mxl111sf_demod_state *state, + fe_modulation_t *modulation) { u8 val; int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); @@ -113,13 +113,13 @@ int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { case 0: - *constellation = QPSK; + *modulation = QPSK; break; case 1: - *constellation = QAM_16; + *modulation = QAM_16; break; case 2: - *constellation = QAM_64; + *modulation = QAM_64; break; } fail: @@ -284,8 +284,7 @@ static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) /* ------------------------------------------------------------------------ */ -static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe) { struct mxl111sf_demod_state *state = fe->demodulator_priv; int ret = 0; @@ -303,7 +302,7 @@ static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, mxl_dbg("()"); if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); + ret = fe->ops.tuner_ops.set_params(fe); if (mxl_fail(ret)) goto fail; msleep(50); @@ -481,13 +480,13 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { struct mxl111sf_demod_state *state = fe->demodulator_priv; - fe_modulation_t constellation; + fe_modulation_t modulation; u16 snr; mxl111sf_demod_calc_snr(state, &snr); - mxl1x1sf_demod_get_tps_constellation(state, &constellation); + mxl1x1sf_demod_get_tps_modulation(state, &modulation); - switch (constellation) { + switch (modulation) { case QPSK: *signal_strength = (snr >= 1300) ? min(65535, snr * 44) : snr * 38; @@ -508,9 +507,9 @@ static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, return 0; } -static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mxl111sf_demod_state *state = fe->demodulator_priv; mxl_dbg("()"); @@ -518,18 +517,18 @@ static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; #endif if (fe->ops.tuner_ops.get_bandwidth) - fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth); + fe->ops.tuner_ops.get_bandwidth(fe, &p->bandwidth_hz); if (fe->ops.tuner_ops.get_frequency) fe->ops.tuner_ops.get_frequency(fe, &p->frequency); - mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP); - mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP); - mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_HP); + mxl1x1sf_demod_get_tps_code_rate(state, &p->code_rate_LP); + mxl1x1sf_demod_get_tps_modulation(state, &p->modulation); mxl1x1sf_demod_get_tps_guard_fft_mode(state, - &p->u.ofdm.transmission_mode); + &p->transmission_mode); mxl1x1sf_demod_get_tps_guard_interval(state, - &p->u.ofdm.guard_interval); + &p->guard_interval); mxl1x1sf_demod_get_tps_hierarchy(state, - &p->u.ofdm.hierarchy_information); + &p->hierarchy); return 0; } @@ -551,10 +550,9 @@ static void mxl111sf_demod_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops mxl111sf_demod_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "MaxLinear MxL111SF DVB-T demodulator", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c index a6341058c4e7..72db6eef4b9c 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c @@ -38,6 +38,8 @@ struct mxl111sf_tuner_state { struct mxl111sf_tuner_config *cfg; + enum mxl_if_freq if_freq; + u32 frequency; u32 bandwidth; }; @@ -186,7 +188,10 @@ static int mxl1x1sf_tuner_set_if_output_freq(struct mxl111sf_tuner_state *state) ctrl = iffcw & 0x00ff; #endif ret = mxl111sf_tuner_write_reg(state, V6_TUNER_IF_FCW_REG, ctrl); - mxl_fail(ret); + if (mxl_fail(ret)) + goto fail; + + state->if_freq = state->cfg->if_freq; fail: return ret; } @@ -267,55 +272,49 @@ static int mxl1x1sf_tuner_loop_thru_ctrl(struct mxl111sf_tuner_state *state, /* ------------------------------------------------------------------------ */ -static int mxl111sf_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int mxl111sf_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; struct mxl111sf_tuner_state *state = fe->tuner_priv; int ret; u8 bw; mxl_dbg("()"); - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - bw = 0; /* ATSC */ - break; - case QAM_64: - case QAM_256: - bw = 1; /* US CABLE */ - break; - default: - err("%s: modulation not set!", __func__); - return -EINVAL; - } - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (delsys) { + case SYS_ATSC: + bw = 0; /* ATSC */ + break; + case SYS_DVBC_ANNEX_B: + bw = 1; /* US CABLE */ + break; + case SYS_DVBT: + switch (c->bandwidth_hz) { + case 6000000: bw = 6; break; - case BANDWIDTH_7_MHZ: + case 7000000: bw = 7; break; - case BANDWIDTH_8_MHZ: + case 8000000: bw = 8; break; default: err("%s: bandwidth not set!", __func__); return -EINVAL; } - } else { + break; + default: err("%s: modulation type not supported!", __func__); return -EINVAL; } - ret = mxl1x1sf_tune_rf(fe, params->frequency, bw); + ret = mxl1x1sf_tune_rf(fe, c->frequency, bw); if (mxl_fail(ret)) goto fail; - state->frequency = params->frequency; - state->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; + state->frequency = c->frequency; + state->bandwidth = c->bandwidth_hz; fail: return ret; } @@ -407,6 +406,54 @@ static int mxl111sf_tuner_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return 0; } +static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, + u32 *frequency) +{ + struct mxl111sf_tuner_state *state = fe->tuner_priv; + + *frequency = 0; + + switch (state->if_freq) { + case MXL_IF_4_0: /* 4.0 MHz */ + *frequency = 4000000; + break; + case MXL_IF_4_5: /* 4.5 MHz */ + *frequency = 4500000; + break; + case MXL_IF_4_57: /* 4.57 MHz */ + *frequency = 4570000; + break; + case MXL_IF_5_0: /* 5.0 MHz */ + *frequency = 5000000; + break; + case MXL_IF_5_38: /* 5.38 MHz */ + *frequency = 5380000; + break; + case MXL_IF_6_0: /* 6.0 MHz */ + *frequency = 6000000; + break; + case MXL_IF_6_28: /* 6.28 MHz */ + *frequency = 6280000; + break; + case MXL_IF_7_2: /* 7.2 MHz */ + *frequency = 7200000; + break; + case MXL_IF_35_25: /* 35.25 MHz */ + *frequency = 35250000; + break; + case MXL_IF_36: /* 36 MHz */ + *frequency = 36000000; + break; + case MXL_IF_36_15: /* 36.15 MHz */ + *frequency = 36150000; + break; + case MXL_IF_44: /* 44 MHz */ + *frequency = 44000000; + break; + } + return 0; +} + static int mxl111sf_tuner_release(struct dvb_frontend *fe) { struct mxl111sf_tuner_state *state = fe->tuner_priv; @@ -436,6 +483,7 @@ static struct dvb_tuner_ops mxl111sf_tuner_tuner_ops = { .get_rf_strength = mxl111sf_get_rf_strength, .get_frequency = mxl111sf_tuner_get_frequency, .get_bandwidth = mxl111sf_tuner_get_bandwidth, + .get_if_frequency = mxl111sf_tuner_get_if_frequency, .release = mxl111sf_tuner_release, }; diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 825a8b242e09..38ef0253d3b5 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c @@ -758,6 +758,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); #define MXL111SF_EP4_BULK_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ .stream = { \ .type = USB_BULK, \ @@ -772,6 +773,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); /* FIXME: works for v6 but not v8 silicon */ #define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ .stream = { \ .type = USB_ISOC, \ @@ -788,6 +790,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); } #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ .stream = { \ .type = USB_BULK, \ @@ -802,6 +805,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); /* FIXME */ #define MXL111SF_EP6_ISOC_STREAMING_CONFIG \ + .size_of_priv = sizeof(struct mxl111sf_adap_state), \ .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ .stream = { \ .type = USB_ISOC, \ @@ -839,8 +843,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 1, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, @@ -883,8 +885,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 1, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, @@ -927,16 +927,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 2, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_BULK_STREAMING_CONFIG, }, { - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, @@ -992,16 +988,12 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { .fe_ioctl_override = mxl111sf_fe_ioctl_override, .num_frontends = 2, .fe = {{ - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_lgdt3305_frontend_attach, .tuner_attach = mxl111sf_attach_tuner, MXL111SF_EP6_ISOC_STREAMING_CONFIG, }, { - .size_of_priv = sizeof(struct mxl111sf_adap_state), - .frontend_attach = mxl111sf_attach_demod, .tuner_attach = mxl111sf_attach_tuner, diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 56acf8e55d50..e53a1061cb8e 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -75,10 +75,18 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) { struct ttusb2_state *st = d->priv; - u8 s[wlen+4],r[64] = { 0 }; + u8 *s, *r = NULL; int ret = 0; - memset(s,0,wlen+4); + s = kzalloc(wlen+4, GFP_KERNEL); + if (!s) + return -ENOMEM; + + r = kzalloc(64, GFP_KERNEL); + if (!r) { + kfree(s); + return -ENOMEM; + } s[0] = 0xaa; s[1] = ++st->id; @@ -94,12 +102,17 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, r[2] != cmd || (rlen > 0 && r[3] != rlen)) { warn("there might have been an error during control message transfer. (rlen = %d, was %d)",rlen,r[3]); + kfree(s); + kfree(r); return -EIO; } if (rlen > 0) memcpy(rbuf, &r[4], rlen); + kfree(s); + kfree(r); + return 0; } @@ -384,7 +397,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num memcpy(&obuf[3], msg[i].buf, msg[i].len); - if (ttusb2_msg(d, CMD_I2C_XFER, obuf, msg[i].len+3, ibuf, obuf[2] + 3) < 0) { + if (ttusb2_msg(d, CMD_I2C_XFER, obuf, obuf[1]+3, ibuf, obuf[2] + 3) < 0) { err("i2c transfer failed."); break; } diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index 2bb8d4cc8d88..5eab468dd904 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -135,9 +135,9 @@ static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } -static int vp702x_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int vp702x_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct vp702x_fe_state *st = fe->demodulator_priv; struct vp702x_device_state *dst = st->d->priv; u32 freq = fep->frequency/1000; @@ -155,14 +155,14 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, cmd[1] = freq & 0xff; cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ - sr = (u64) (fep->u.qpsk.symbol_rate/1000) << 20; + sr = (u64) (fep->symbol_rate/1000) << 20; do_div(sr,88000); cmd[3] = (sr >> 12) & 0xff; cmd[4] = (sr >> 4) & 0xff; cmd[5] = (sr << 4) & 0xf0; deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", - fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, + fep->frequency, freq, freq, fep->symbol_rate, (unsigned long) sr, (unsigned long) sr); /* if (fep->inversion == INVERSION_ON) @@ -171,7 +171,7 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, if (st->voltage == SEC_VOLTAGE_18) cmd[6] |= 0x40; -/* if (fep->u.qpsk.symbol_rate > 8000000) +/* if (fep->symbol_rate > 8000000) cmd[6] |= 0x20; if (fep->frequency < 1531000) @@ -211,13 +211,6 @@ static int vp702x_fe_sleep(struct dvb_frontend *fe) return 0; } -static int vp702x_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - deb_fe("%s\n",__func__); - return 0; -} - static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { @@ -350,9 +343,9 @@ error: static struct dvb_frontend_ops vp702x_fe_ops = { + .delsys = { SYS_DVBS }, .info = { .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, /* kHz for QPSK frontends */ @@ -371,7 +364,6 @@ static struct dvb_frontend_ops vp702x_fe_ops = { .sleep = vp702x_fe_sleep, .set_frontend = vp702x_fe_set_frontend, - .get_frontend = vp702x_fe_get_frontend, .get_tune_settings = vp702x_fe_get_tune_settings, .read_status = vp702x_fe_read_status, diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c index 8452eef90322..b8825b18c003 100644 --- a/drivers/media/dvb/dvb-usb/vp7045-fe.c +++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c @@ -103,9 +103,9 @@ static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front return 0; } -static int vp7045_fe_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int vp7045_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct vp7045_fe_state *state = fe->demodulator_priv; u8 buf[5]; u32 freq = fep->frequency / 1000; @@ -115,25 +115,24 @@ static int vp7045_fe_set_frontend(struct dvb_frontend* fe, buf[2] = freq & 0xff; buf[3] = 0; - switch (fep->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: buf[4] = 8; break; - case BANDWIDTH_7_MHZ: buf[4] = 7; break; - case BANDWIDTH_6_MHZ: buf[4] = 6; break; - case BANDWIDTH_AUTO: return -EOPNOTSUPP; - default: - return -EINVAL; + switch (fep->bandwidth_hz) { + case 8000000: + buf[4] = 8; + break; + case 7000000: + buf[4] = 7; + break; + case 6000000: + buf[4] = 6; + break; + default: + return -EINVAL; } vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200); return 0; } -static int vp7045_fe_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) -{ - return 0; -} - static void vp7045_fe_release(struct dvb_frontend* fe) { struct vp7045_fe_state *state = fe->demodulator_priv; @@ -159,9 +158,9 @@ error: static struct dvb_frontend_ops vp7045_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Twinhan VP7045/46 USB DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 1000, @@ -181,7 +180,6 @@ static struct dvb_frontend_ops vp7045_fe_ops = { .sleep = vp7045_fe_sleep, .set_frontend = vp7045_fe_set_frontend, - .get_frontend = vp7045_fe_get_frontend, .get_tune_settings = vp7045_fe_get_tune_settings, .read_status = vp7045_fe_read_status, diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c index 489ae8245867..d1a1a1324ef8 100644 --- a/drivers/media/dvb/firewire/firedtv-avc.c +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -335,7 +335,7 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand) * (not supported by the AVC standard) */ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { struct avc_command_frame *c = (void *)fdtv->avc_data; @@ -349,15 +349,15 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, else c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; - c->operand[4] = (params->frequency >> 24) & 0xff; - c->operand[5] = (params->frequency >> 16) & 0xff; - c->operand[6] = (params->frequency >> 8) & 0xff; - c->operand[7] = params->frequency & 0xff; + c->operand[4] = (p->frequency >> 24) & 0xff; + c->operand[5] = (p->frequency >> 16) & 0xff; + c->operand[6] = (p->frequency >> 8) & 0xff; + c->operand[7] = p->frequency & 0xff; - c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; - c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; + c->operand[8] = ((p->symbol_rate / 1000) >> 8) & 0xff; + c->operand[9] = (p->symbol_rate / 1000) & 0xff; - switch (params->u.qpsk.fec_inner) { + switch (p->fec_inner) { case FEC_1_2: c->operand[10] = 0x1; break; case FEC_2_3: c->operand[10] = 0x2; break; case FEC_3_4: c->operand[10] = 0x3; break; @@ -392,10 +392,11 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, default: c->operand[13] = 0x2; break; } switch (fdtv->fe.dtv_property_cache.rolloff) { - case ROLLOFF_AUTO: c->operand[14] = 0x2; break; case ROLLOFF_35: c->operand[14] = 0x2; break; case ROLLOFF_20: c->operand[14] = 0x0; break; case ROLLOFF_25: c->operand[14] = 0x1; break; + case ROLLOFF_AUTO: + default: c->operand[14] = 0x2; break; /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */ } switch (fdtv->fe.dtv_property_cache.pilot) { @@ -415,7 +416,7 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv, } static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { struct avc_command_frame *c = (void *)fdtv->avc_data; @@ -434,8 +435,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, | 1 << 4 /* Frequency */ | 1 << 3 /* Symbol_Rate */ | 0 << 2 /* FEC_outer */ - | (params->u.qam.fec_inner != FEC_AUTO ? 1 << 1 : 0) - | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0); + | (p->fec_inner != FEC_AUTO ? 1 << 1 : 0) + | (p->modulation != QAM_AUTO ? 1 << 0 : 0); /* multiplex_valid_flags, low byte */ c->operand[6] = 0 << 7 /* NetworkID */ @@ -446,15 +447,15 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, c->operand[9] = 0x00; c->operand[10] = 0x00; - c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); - c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff; - c->operand[13] = (params->frequency / 4000) & 0xff; - c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; - c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; - c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; + c->operand[11] = (((p->frequency / 4000) >> 16) & 0xff) | (2 << 6); + c->operand[12] = ((p->frequency / 4000) >> 8) & 0xff; + c->operand[13] = (p->frequency / 4000) & 0xff; + c->operand[14] = ((p->symbol_rate / 1000) >> 12) & 0xff; + c->operand[15] = ((p->symbol_rate / 1000) >> 4) & 0xff; + c->operand[16] = ((p->symbol_rate / 1000) << 4) & 0xf0; c->operand[17] = 0x00; - switch (params->u.qpsk.fec_inner) { + switch (p->fec_inner) { case FEC_1_2: c->operand[18] = 0x1; break; case FEC_2_3: c->operand[18] = 0x2; break; case FEC_3_4: c->operand[18] = 0x3; break; @@ -466,7 +467,7 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, default: c->operand[18] = 0x0; } - switch (params->u.qam.modulation) { + switch (p->modulation) { case QAM_16: c->operand[19] = 0x08; break; case QAM_32: c->operand[19] = 0x10; break; case QAM_64: c->operand[19] = 0x18; break; @@ -483,9 +484,8 @@ static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv, } static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { - struct dvb_ofdm_parameters *ofdm = ¶ms->u.ofdm; struct avc_command_frame *c = (void *)fdtv->avc_data; c->opcode = AVC_OPCODE_DSD; @@ -500,42 +500,42 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, c->operand[5] = 0 << 7 /* reserved */ | 1 << 6 /* CenterFrequency */ - | (ofdm->bandwidth != BANDWIDTH_AUTO ? 1 << 5 : 0) - | (ofdm->constellation != QAM_AUTO ? 1 << 4 : 0) - | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0) - | (ofdm->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) - | (ofdm->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) - | (ofdm->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); + | (p->bandwidth_hz != 0 ? 1 << 5 : 0) + | (p->modulation != QAM_AUTO ? 1 << 4 : 0) + | (p->hierarchy != HIERARCHY_AUTO ? 1 << 3 : 0) + | (p->code_rate_HP != FEC_AUTO ? 1 << 2 : 0) + | (p->code_rate_LP != FEC_AUTO ? 1 << 1 : 0) + | (p->guard_interval != GUARD_INTERVAL_AUTO ? 1 << 0 : 0); /* multiplex_valid_flags, low byte */ c->operand[6] = 0 << 7 /* NetworkID */ - | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) + | (p->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0) | 0 << 5 /* OtherFrequencyFlag */ | 0 << 0 /* reserved */ ; c->operand[7] = 0x0; - c->operand[8] = (params->frequency / 10) >> 24; - c->operand[9] = ((params->frequency / 10) >> 16) & 0xff; - c->operand[10] = ((params->frequency / 10) >> 8) & 0xff; - c->operand[11] = (params->frequency / 10) & 0xff; - - switch (ofdm->bandwidth) { - case BANDWIDTH_7_MHZ: c->operand[12] = 0x20; break; - case BANDWIDTH_8_MHZ: - case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ - case BANDWIDTH_AUTO: + c->operand[8] = (p->frequency / 10) >> 24; + c->operand[9] = ((p->frequency / 10) >> 16) & 0xff; + c->operand[10] = ((p->frequency / 10) >> 8) & 0xff; + c->operand[11] = (p->frequency / 10) & 0xff; + + switch (p->bandwidth_hz) { + case 7000000: c->operand[12] = 0x20; break; + case 8000000: + case 6000000: /* not defined by AVC spec */ + case 0: default: c->operand[12] = 0x00; } - switch (ofdm->constellation) { + switch (p->modulation) { case QAM_16: c->operand[13] = 1 << 6; break; case QAM_64: c->operand[13] = 2 << 6; break; case QPSK: default: c->operand[13] = 0x00; } - switch (ofdm->hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_1: c->operand[13] |= 1 << 3; break; case HIERARCHY_2: c->operand[13] |= 2 << 3; break; case HIERARCHY_4: c->operand[13] |= 3 << 3; break; @@ -544,7 +544,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: break; } - switch (ofdm->code_rate_HP) { + switch (p->code_rate_HP) { case FEC_2_3: c->operand[13] |= 1; break; case FEC_3_4: c->operand[13] |= 2; break; case FEC_5_6: c->operand[13] |= 3; break; @@ -553,7 +553,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: break; } - switch (ofdm->code_rate_LP) { + switch (p->code_rate_LP) { case FEC_2_3: c->operand[14] = 1 << 5; break; case FEC_3_4: c->operand[14] = 2 << 5; break; case FEC_5_6: c->operand[14] = 3 << 5; break; @@ -562,7 +562,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: c->operand[14] = 0x00; break; } - switch (ofdm->guard_interval) { + switch (p->guard_interval) { case GUARD_INTERVAL_1_16: c->operand[14] |= 1 << 3; break; case GUARD_INTERVAL_1_8: c->operand[14] |= 2 << 3; break; case GUARD_INTERVAL_1_4: c->operand[14] |= 3 << 3; break; @@ -571,7 +571,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, default: break; } - switch (ofdm->transmission_mode) { + switch (p->transmission_mode) { case TRANSMISSION_MODE_8K: c->operand[14] |= 1 << 1; break; case TRANSMISSION_MODE_2K: case TRANSMISSION_MODE_AUTO: @@ -585,7 +585,7 @@ static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv, } int avc_tuner_dsd(struct firedtv *fdtv, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *p) { struct avc_command_frame *c = (void *)fdtv->avc_data; int pos, ret; @@ -597,9 +597,9 @@ int avc_tuner_dsd(struct firedtv *fdtv, switch (fdtv->type) { case FIREDTV_DVB_S: - case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break; - case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break; - case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break; + case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, p); break; + case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, p); break; + case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, p); break; default: BUG(); } diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index fd8bbbfa5c59..eb7496eab130 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -203,7 +203,9 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name) if (err) goto fail_rem_frontend; - dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); + if (err) + goto fail_disconnect_frontend; fdtv_frontend_init(fdtv, name); err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); @@ -218,6 +220,7 @@ int fdtv_dvb_register(struct firedtv *fdtv, const char *name) fail_net_release: dvb_net_release(&fdtv->dvbnet); +fail_disconnect_frontend: fdtv->demux.dmx.close(&fdtv->demux.dmx); fail_rem_frontend: fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend); diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c index 8748a61be73d..6fe9793b98b3 100644 --- a/drivers/media/dvb/firewire/firedtv-fe.c +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -141,28 +141,12 @@ static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) return -EOPNOTSUPP; } -static int fdtv_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int fdtv_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct firedtv *fdtv = fe->sec_priv; - return avc_tuner_dsd(fdtv, params); -} - -static int fdtv_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - return -EOPNOTSUPP; -} - -static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp) -{ - return 0; -} - -static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp) -{ - return 0; + return avc_tuner_dsd(fdtv, p); } void fdtv_frontend_init(struct firedtv *fdtv, const char *name) @@ -174,10 +158,6 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) ops->sleep = fdtv_sleep; ops->set_frontend = fdtv_set_frontend; - ops->get_frontend = fdtv_get_frontend; - - ops->get_property = fdtv_get_property; - ops->set_property = fdtv_set_property; ops->read_status = fdtv_read_status; ops->read_ber = fdtv_read_ber; @@ -192,7 +172,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) switch (fdtv->type) { case FIREDTV_DVB_S: - fi->type = FE_QPSK; + ops->delsys[0] = SYS_DVBS; fi->frequency_min = 950000; fi->frequency_max = 2150000; @@ -211,7 +191,8 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) break; case FIREDTV_DVB_S2: - fi->type = FE_QPSK; + ops->delsys[0] = SYS_DVBS; + ops->delsys[1] = SYS_DVBS2; fi->frequency_min = 950000; fi->frequency_max = 2150000; @@ -231,7 +212,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) break; case FIREDTV_DVB_C: - fi->type = FE_QAM; + ops->delsys[0] = SYS_DVBC_ANNEX_A; fi->frequency_min = 47000000; fi->frequency_max = 866000000; @@ -249,7 +230,7 @@ void fdtv_frontend_init(struct firedtv *fdtv, const char *name) break; case FIREDTV_DVB_T: - fi->type = FE_OFDM; + ops->delsys[0] = SYS_DVBT; fi->frequency_min = 49000000; fi->frequency_max = 861000000; diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h index bd00b04e079d..4fdcd8cb7530 100644 --- a/drivers/media/dvb/firewire/firedtv.h +++ b/drivers/media/dvb/firewire/firedtv.h @@ -112,8 +112,8 @@ struct firedtv { /* firedtv-avc.c */ int avc_recv(struct firedtv *fdtv, void *data, size_t length); int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); -struct dvb_frontend_parameters; -int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params); +struct dtv_frontend_properties; +int avc_tuner_dsd(struct firedtv *fdtv, struct dtv_frontend_properties *params); int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]); int avc_tuner_get_ts(struct firedtv *fdtv); int avc_identify_subunit(struct firedtv *fdtv); diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 4a2d2e6c91ab..ebb5ed7a7783 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -404,6 +404,13 @@ config DVB_EC100 help Say Y when you want to support this frontend. +config DVB_HD29L2 + tristate "HDIC HD29L2" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Say Y when you want to support this frontend. + config DVB_STV0367 tristate "ST STV0367 based" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index f639f6781551..00a20636df62 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_DVB_STV090x) += stv090x.o obj-$(CONFIG_DVB_STV6110x) += stv6110x.o obj-$(CONFIG_DVB_ISL6423) += isl6423.o obj-$(CONFIG_DVB_EC100) += ec100.o +obj-$(CONFIG_DVB_HD29L2) += hd29l2.o obj-$(CONFIG_DVB_DS3000) += ds3000.o obj-$(CONFIG_DVB_MB86A16) += mb86a16.o obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 345311c33383..6bcbcf543b38 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -2,6 +2,7 @@ * Afatech AF9013 demodulator driver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * @@ -21,25 +22,15 @@ * */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/firmware.h> - -#include "dvb_frontend.h" #include "af9013_priv.h" -#include "af9013.h" int af9013_debug; +module_param_named(debug, af9013_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); struct af9013_state { struct i2c_adapter *i2c; - struct dvb_frontend frontend; - + struct dvb_frontend fe; struct af9013_config config; /* tuner/demod RF and IF AGC limits used for signal strength calc */ @@ -48,107 +39,178 @@ struct af9013_state { u32 ber; u32 ucblocks; u16 snr; - u32 frequency; - unsigned long next_statistics_check; + u32 bandwidth_hz; + fe_status_t fe_status; + unsigned long set_frontend_jiffies; + unsigned long read_status_jiffies; + bool first_tune; + bool i2c_gate_state; + unsigned int statistics_step:3; + struct delayed_work statistics_work; }; -static u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; - -static int af9013_write_regs(struct af9013_state *state, u8 mbox, u16 reg, - u8 *val, u8 len) +/* write multiple registers */ +static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, + const u8 *val, int len) { + int ret; u8 buf[3+len]; - struct i2c_msg msg = { - .addr = state->config.demod_address, - .flags = 0, - .len = sizeof(buf), - .buf = buf }; - - buf[0] = reg >> 8; - buf[1] = reg & 0xff; + struct i2c_msg msg[1] = { + { + .addr = priv->config.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; memcpy(&buf[3], val, len); - if (i2c_transfer(state->i2c, &msg, 1) != 1) { - warn("I2C write failed reg:%04x len:%d", reg, len); - return -EREMOTEIO; + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed=%d reg=%04x len=%d", ret, reg, len); + ret = -EREMOTEIO; } - return 0; + return ret; } -static int af9013_write_ofdm_regs(struct af9013_state *state, u16 reg, u8 *val, - u8 len) +/* read multiple registers */ +static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, + u8 *val, int len) { - u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(0 << 6)|(0 << 7); - return af9013_write_regs(state, mbox, reg, val, len); + int ret; + u8 buf[3]; + struct i2c_msg msg[2] = { + { + .addr = priv->config.i2c_addr, + .flags = 0, + .len = 3, + .buf = buf, + }, { + .addr = priv->config.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + buf[0] = (reg >> 8) & 0xff; + buf[1] = (reg >> 0) & 0xff; + buf[2] = mbox; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + warn("i2c rd failed=%d reg=%04x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + return ret; } -static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, - u8 len) +/* write multiple registers */ +static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, + int len) +{ + int ret, i; + u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); + + if ((priv->config.ts_mode == AF9013_TS_USB) && + ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { + mbox |= ((len - 1) << 2); + ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); + } else { + for (i = 0; i < len; i++) { + ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1); + if (ret) + goto err; + } + } + +err: + return 0; +} + +/* read multiple registers */ +static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len) { - u8 mbox = (1 << 0)|(1 << 1)|((len - 1) << 2)|(1 << 6)|(1 << 7); - return af9013_write_regs(state, mbox, reg, val, len); + int ret, i; + u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0); + + if ((priv->config.ts_mode == AF9013_TS_USB) && + ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { + mbox |= ((len - 1) << 2); + ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len); + } else { + for (i = 0; i < len; i++) { + ret = af9013_rd_regs_i2c(priv, mbox, reg+i, val+i, 1); + if (ret) + goto err; + } + } + +err: + return 0; } /* write single register */ -static int af9013_write_reg(struct af9013_state *state, u16 reg, u8 val) +static int af9013_wr_reg(struct af9013_state *priv, u16 reg, u8 val) { - return af9013_write_ofdm_regs(state, reg, &val, 1); + return af9013_wr_regs(priv, reg, &val, 1); } /* read single register */ -static int af9013_read_reg(struct af9013_state *state, u16 reg, u8 *val) +static int af9013_rd_reg(struct af9013_state *priv, u16 reg, u8 *val) { - u8 obuf[3] = { reg >> 8, reg & 0xff, 0 }; - u8 ibuf[1]; - struct i2c_msg msg[2] = { - { - .addr = state->config.demod_address, - .flags = 0, - .len = sizeof(obuf), - .buf = obuf - }, { - .addr = state->config.demod_address, - .flags = I2C_M_RD, - .len = sizeof(ibuf), - .buf = ibuf - } - }; + return af9013_rd_regs(priv, reg, val, 1); +} - if (i2c_transfer(state->i2c, msg, 2) != 2) { - warn("I2C read failed reg:%04x", reg); - return -EREMOTEIO; - } - *val = ibuf[0]; - return 0; +static int af9013_write_ofsm_regs(struct af9013_state *state, u16 reg, u8 *val, + u8 len) +{ + u8 mbox = (1 << 7)|(1 << 6)|((len - 1) << 2)|(1 << 1)|(1 << 0); + return af9013_wr_regs_i2c(state, mbox, reg, val, len); } -static int af9013_write_reg_bits(struct af9013_state *state, u16 reg, u8 pos, - u8 len, u8 val) +static int af9013_wr_reg_bits(struct af9013_state *state, u16 reg, int pos, + int len, u8 val) { int ret; u8 tmp, mask; - ret = af9013_read_reg(state, reg, &tmp); - if (ret) - return ret; + /* no need for read if whole reg is written */ + if (len != 8) { + ret = af9013_rd_reg(state, reg, &tmp); + if (ret) + return ret; - mask = regmask[len - 1] << pos; - tmp = (tmp & ~mask) | ((val << pos) & mask); + mask = (0xff >> (8 - len)) << pos; + val <<= pos; + tmp &= ~mask; + val |= tmp; + } - return af9013_write_reg(state, reg, tmp); + return af9013_wr_reg(state, reg, val); } -static int af9013_read_reg_bits(struct af9013_state *state, u16 reg, u8 pos, - u8 len, u8 *val) +static int af9013_rd_reg_bits(struct af9013_state *state, u16 reg, int pos, + int len, u8 *val) { int ret; u8 tmp; - ret = af9013_read_reg(state, reg, &tmp); + ret = af9013_rd_reg(state, reg, &tmp); if (ret) return ret; - *val = (tmp >> pos) & regmask[len - 1]; + + *val = (tmp >> pos); + *val &= (0xff >> (8 - len)); + return 0; } @@ -157,10 +219,13 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) int ret; u8 pos; u16 addr; - deb_info("%s: gpio:%d gpioval:%02x\n", __func__, gpio, gpioval); -/* GPIO0 & GPIO1 0xd735 - GPIO2 & GPIO3 0xd736 */ + dbg("%s: gpio=%d gpioval=%02x", __func__, gpio, gpioval); + + /* + * GPIO0 & GPIO1 0xd735 + * GPIO2 & GPIO3 0xd736 + */ switch (gpio) { case 0: @@ -175,7 +240,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) default: err("invalid gpio:%d\n", gpio); ret = -EINVAL; - goto error; + goto err; }; switch (gpio) { @@ -190,16 +255,21 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) break; }; - ret = af9013_write_reg_bits(state, addr, pos, 4, gpioval); + ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval); + if (ret) + goto err; -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } static u32 af913_div(u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - deb_info("%s: a:%d b:%d x:%d\n", __func__, a, b, x); + + dbg("%s: a=%d b=%d x=%d", __func__, a, b, x); if (a > b) { c = a / b; @@ -216,205 +286,407 @@ static u32 af913_div(u32 a, u32 b, u32 x) } r = (c << (u32)x) + r; - deb_info("%s: a:%d b:%d x:%d r:%d r:%x\n", __func__, a, b, x, r, r); + dbg("%s: a=%d b=%d x=%d r=%x", __func__, a, b, x, r); return r; } -static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw) +static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) { - int ret, i, j, found; - deb_info("%s: adc_clock:%d bw:%d\n", __func__, - state->config.adc_clock, bw); - - /* lookup coeff from table */ - for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) { - if (coeff_table[i].adc_clock == state->config.adc_clock && - coeff_table[i].bw == bw) { - found = 1; - break; - } - } + int ret, i; + u8 tmp; - if (!found) { - err("invalid bw or clock"); - ret = -EINVAL; - goto error; + dbg("%s: onoff=%d", __func__, onoff); + + /* enable reset */ + ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 1); + if (ret) + goto err; + + /* start reset mechanism */ + ret = af9013_wr_reg(state, 0xaeff, 1); + if (ret) + goto err; + + /* wait reset performs */ + for (i = 0; i < 150; i++) { + ret = af9013_rd_reg_bits(state, 0xd417, 1, 1, &tmp); + if (ret) + goto err; + + if (tmp) + break; /* reset done */ + + usleep_range(5000, 25000); } - deb_info("%s: coeff: ", __func__); - debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info); + if (!tmp) + return -ETIMEDOUT; - /* program */ - for (j = 0; j < sizeof(coeff_table[i].val); j++) { - ret = af9013_write_reg(state, 0xae00 + j, - coeff_table[i].val[j]); + if (onoff) { + /* clear reset */ + ret = af9013_wr_reg_bits(state, 0xd417, 1, 1, 0); if (ret) - break; + goto err; + + /* disable reset */ + ret = af9013_wr_reg_bits(state, 0xd417, 4, 1, 0); + + /* power on */ + ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 0); + } else { + /* power off */ + ret = af9013_wr_reg_bits(state, 0xd73a, 3, 1, 1); } -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + dbg("%s", __func__); + + /* reset and start BER counter */ + ret = af9013_wr_reg_bits(state, 0xd391, 4, 1, 1); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_set_adc_ctrl(struct af9013_state *state) +static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) { + struct af9013_state *state = fe->demodulator_priv; int ret; - u8 buf[3], tmp, i; - u32 adc_cw; + u8 buf[5]; - deb_info("%s: adc_clock:%d\n", __func__, state->config.adc_clock); + dbg("%s", __func__); - /* adc frequency type */ - switch (state->config.adc_clock) { - case 28800: /* 28.800 MHz */ - tmp = 0; - break; - case 20480: /* 20.480 MHz */ - tmp = 1; + /* check if error bit count is ready */ + ret = af9013_rd_reg_bits(state, 0xd391, 4, 1, &buf[0]); + if (ret) + goto err; + + if (!buf[0]) { + dbg("%s: not ready", __func__); + return 0; + } + + ret = af9013_rd_regs(state, 0xd387, buf, 5); + if (ret) + goto err; + + state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + state->ucblocks += (buf[4] << 8) | buf[3]; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_snr_start(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + dbg("%s", __func__); + + /* start SNR meas */ + ret = af9013_wr_reg_bits(state, 0xd2e1, 3, 1, 1); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_snr_result(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret, i, len; + u8 buf[3], tmp; + u32 snr_val; + const struct af9013_snr *uninitialized_var(snr_lut); + + dbg("%s", __func__); + + /* check if SNR ready */ + ret = af9013_rd_reg_bits(state, 0xd2e1, 3, 1, &tmp); + if (ret) + goto err; + + if (!tmp) { + dbg("%s: not ready", __func__); + return 0; + } + + /* read value */ + ret = af9013_rd_regs(state, 0xd2e3, buf, 3); + if (ret) + goto err; + + snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + /* read current modulation */ + ret = af9013_rd_reg(state, 0xd3c1, &tmp); + if (ret) + goto err; + + switch ((tmp >> 6) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_lut); + snr_lut = qpsk_snr_lut; break; - case 28000: /* 28.000 MHz */ - tmp = 2; + case 1: + len = ARRAY_SIZE(qam16_snr_lut); + snr_lut = qam16_snr_lut; break; - case 25000: /* 25.000 MHz */ - tmp = 3; + case 2: + len = ARRAY_SIZE(qam64_snr_lut); + snr_lut = qam64_snr_lut; break; default: - err("invalid xtal"); - return -EINVAL; + goto err; + break; } - adc_cw = af913_div(state->config.adc_clock*1000, 1000000ul, 19ul); + for (i = 0; i < len; i++) { + tmp = snr_lut[i].snr; - buf[0] = (u8) ((adc_cw & 0x000000ff)); - buf[1] = (u8) ((adc_cw & 0x0000ff00) >> 8); - buf[2] = (u8) ((adc_cw & 0x00ff0000) >> 16); + if (snr_val < snr_lut[i].val) + break; + } + state->snr = tmp * 10; /* dB/10 */ - deb_info("%s: adc_cw:", __func__); - debug_dump(buf, sizeof(buf), deb_info); + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_statistics_signal_strength(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret = 0; + u8 buf[2], rf_gain, if_gain; + int signal_strength; + + dbg("%s", __func__); + + if (!state->signal_strength_en) + return 0; + + ret = af9013_rd_regs(state, 0xd07c, buf, 2); + if (ret) + goto err; + + rf_gain = buf[0]; + if_gain = buf[1]; + + signal_strength = (0xffff / \ + (9 * (state->rf_50 + state->if_50) - \ + 11 * (state->rf_80 + state->if_80))) * \ + (10 * (rf_gain + if_gain) - \ + 11 * (state->rf_80 + state->if_80)); + if (signal_strength < 0) + signal_strength = 0; + else if (signal_strength > 0xffff) + signal_strength = 0xffff; + + state->signal_strength = signal_strength; - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, 0xd180 + i, buf[i]); - if (ret) - goto error; - } - ret = af9013_write_reg_bits(state, 0x9bd2, 0, 4, tmp); -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw) +static void af9013_statistics_work(struct work_struct *work) { int ret; - u16 addr; - u8 buf[3], i, j; - u32 adc_freq, freq_cw; - s8 bfs_spec_inv; - int if_sample_freq; - - for (j = 0; j < 3; j++) { - if (j == 0) { - addr = 0xd140; /* fcw normal */ - bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; - } else if (j == 1) { - addr = 0x9be7; /* fcw dummy ram */ - bfs_spec_inv = state->config.rf_spec_inv ? -1 : 1; - } else { - addr = 0x9bea; /* fcw inverted */ - bfs_spec_inv = state->config.rf_spec_inv ? 1 : -1; - } + struct af9013_state *state = container_of(work, + struct af9013_state, statistics_work.work); + unsigned int next_msec; + + /* update only signal strength when demod is not locked */ + if (!(state->fe_status & FE_HAS_LOCK)) { + state->statistics_step = 0; + state->ber = 0; + state->snr = 0; + } + + switch (state->statistics_step) { + default: + state->statistics_step = 0; + case 0: + ret = af9013_statistics_signal_strength(&state->fe); + state->statistics_step++; + next_msec = 300; + break; + case 1: + ret = af9013_statistics_snr_start(&state->fe); + state->statistics_step++; + next_msec = 200; + break; + case 2: + ret = af9013_statistics_ber_unc_start(&state->fe); + state->statistics_step++; + next_msec = 1000; + break; + case 3: + ret = af9013_statistics_snr_result(&state->fe); + state->statistics_step++; + next_msec = 400; + break; + case 4: + ret = af9013_statistics_ber_unc_result(&state->fe); + state->statistics_step++; + next_msec = 100; + break; + } - adc_freq = state->config.adc_clock * 1000; - if_sample_freq = state->config.tuner_if * 1000; + schedule_delayed_work(&state->statistics_work, + msecs_to_jiffies(next_msec)); - /* TDA18271 uses different sampling freq for every bw */ - if (state->config.tuner == AF9013_TUNER_TDA18271) { - switch (bw) { - case BANDWIDTH_6_MHZ: - if_sample_freq = 3300000; /* 3.3 MHz */ - break; - case BANDWIDTH_7_MHZ: - if_sample_freq = 3500000; /* 3.5 MHz */ - break; - case BANDWIDTH_8_MHZ: - default: - if_sample_freq = 4000000; /* 4.0 MHz */ - break; - } - } else if (state->config.tuner == AF9013_TUNER_TDA18218) { - switch (bw) { - case BANDWIDTH_6_MHZ: - if_sample_freq = 3000000; /* 3 MHz */ - break; - case BANDWIDTH_7_MHZ: - if_sample_freq = 3500000; /* 3.5 MHz */ - break; - case BANDWIDTH_8_MHZ: - default: - if_sample_freq = 4000000; /* 4 MHz */ + return; +} + +static int af9013_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 800; + fesettings->step_size = 0; + fesettings->max_drift = 0; + + return 0; +} + +static int af9013_set_frontend(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, i, sampling_freq; + bool auto_mode, spec_inv; + u8 buf[6]; + u32 if_frequency, freq_cw; + + dbg("%s: frequency=%d bandwidth_hz=%d", __func__, + c->frequency, c->bandwidth_hz); + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + /* program CFOE coefficients */ + if (c->bandwidth_hz != state->bandwidth_hz) { + for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { + if (coeff_lut[i].clock == state->config.clock && + coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { break; } } - while (if_sample_freq > (adc_freq / 2)) - if_sample_freq = if_sample_freq - adc_freq; + ret = af9013_wr_regs(state, 0xae00, coeff_lut[i].val, + sizeof(coeff_lut[i].val)); + } - if (if_sample_freq >= 0) - bfs_spec_inv = bfs_spec_inv * (-1); + /* program frequency control */ + if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) { + /* get used IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); else - if_sample_freq = if_sample_freq * (-1); + if_frequency = state->config.if_frequency; + + sampling_freq = if_frequency; - freq_cw = af913_div(if_sample_freq, adc_freq, 23ul); + while (sampling_freq > (state->config.clock / 2)) + sampling_freq -= state->config.clock; - if (bfs_spec_inv == -1) - freq_cw = 0x00800000 - freq_cw; + if (sampling_freq < 0) { + sampling_freq *= -1; + spec_inv = state->config.spec_inv; + } else { + spec_inv = !state->config.spec_inv; + } - buf[0] = (u8) ((freq_cw & 0x000000ff)); - buf[1] = (u8) ((freq_cw & 0x0000ff00) >> 8); - buf[2] = (u8) ((freq_cw & 0x007f0000) >> 16); + freq_cw = af913_div(sampling_freq, state->config.clock, 23); + if (spec_inv) + freq_cw = 0x800000 - freq_cw; - deb_info("%s: freq_cw:", __func__); - debug_dump(buf, sizeof(buf), deb_info); + buf[0] = (freq_cw >> 0) & 0xff; + buf[1] = (freq_cw >> 8) & 0xff; + buf[2] = (freq_cw >> 16) & 0x7f; - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, addr++, buf[i]); - if (ret) - goto error; - } + freq_cw = 0x800000 - freq_cw; + + buf[3] = (freq_cw >> 0) & 0xff; + buf[4] = (freq_cw >> 8) & 0xff; + buf[5] = (freq_cw >> 16) & 0x7f; + + ret = af9013_wr_regs(state, 0xd140, buf, 3); + if (ret) + goto err; + + ret = af9013_wr_regs(state, 0x9be7, buf, 6); + if (ret) + goto err; } -error: - return ret; -} -static int af9013_set_ofdm_params(struct af9013_state *state, - struct dvb_ofdm_parameters *params, u8 *auto_mode) -{ - int ret; - u8 i, buf[3] = {0, 0, 0}; - *auto_mode = 0; /* set if parameters are requested to auto set */ + /* clear TPS lock flag */ + ret = af9013_wr_reg_bits(state, 0xd330, 3, 1, 1); + if (ret) + goto err; + + /* clear MPEG2 lock flag */ + ret = af9013_wr_reg_bits(state, 0xd507, 6, 1, 0); + if (ret) + goto err; + + /* empty channel function */ + ret = af9013_wr_reg_bits(state, 0x9bfe, 0, 1, 0); + if (ret) + goto err; - /* Try auto-detect transmission parameters in case of AUTO requested or - garbage parameters given by application for compatibility. - MPlayer seems to provide garbage parameters currently. */ + /* empty DVB-T channel function */ + ret = af9013_wr_reg_bits(state, 0x9bc2, 0, 1, 0); + if (ret) + goto err; + + /* transmission parameters */ + auto_mode = false; + memset(buf, 0, 3); - switch (params->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case TRANSMISSION_MODE_2K: break; case TRANSMISSION_MODE_8K: buf[0] |= (1 << 0); break; default: - deb_info("%s: invalid transmission_mode\n", __func__); - *auto_mode = 1; + dbg("%s: invalid transmission_mode", __func__); + auto_mode = 1; } - switch (params->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case GUARD_INTERVAL_1_32: break; case GUARD_INTERVAL_1_16: @@ -427,13 +699,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 2); break; default: - deb_info("%s: invalid guard_interval\n", __func__); - *auto_mode = 1; + dbg("%s: invalid guard_interval", __func__); + auto_mode = 1; } - switch (params->hierarchy_information) { + switch (c->hierarchy) { case HIERARCHY_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -446,13 +719,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[0] |= (3 << 4); break; default: - deb_info("%s: invalid hierarchy_information\n", __func__); - *auto_mode = 1; + dbg("%s: invalid hierarchy", __func__); + auto_mode = 1; }; - switch (params->constellation) { + switch (c->modulation) { case QAM_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case QPSK: break; case QAM_16: @@ -462,16 +736,17 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[1] |= (2 << 6); break; default: - deb_info("%s: invalid constellation\n", __func__); - *auto_mode = 1; + dbg("%s: invalid modulation", __func__); + auto_mode = 1; } /* Use HP. How and which case we can switch to LP? */ buf[1] |= (1 << 4); - switch (params->code_rate_HP) { + switch (c->code_rate_HP) { case FEC_AUTO: - *auto_mode = 1; + auto_mode = 1; + break; case FEC_1_2: break; case FEC_2_3: @@ -487,16 +762,14 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[2] |= (4 << 0); break; default: - deb_info("%s: invalid code_rate_HP\n", __func__); - *auto_mode = 1; + dbg("%s: invalid code_rate_HP", __func__); + auto_mode = 1; } - switch (params->code_rate_LP) { + switch (c->code_rate_LP) { case FEC_AUTO: - /* if HIERARCHY_NONE and FEC_NONE then LP FEC is set to FEC_AUTO - by dvb_frontend.c for compatibility */ - if (params->hierarchy_information != HIERARCHY_NONE) - *auto_mode = 1; + auto_mode = 1; + break; case FEC_1_2: break; case FEC_2_3: @@ -512,709 +785,373 @@ static int af9013_set_ofdm_params(struct af9013_state *state, buf[2] |= (4 << 3); break; case FEC_NONE: - if (params->hierarchy_information == HIERARCHY_AUTO) - break; + break; default: - deb_info("%s: invalid code_rate_LP\n", __func__); - *auto_mode = 1; + dbg("%s: invalid code_rate_LP", __func__); + auto_mode = 1; } - switch (params->bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: break; - case BANDWIDTH_7_MHZ: + case 7000000: buf[1] |= (1 << 2); break; - case BANDWIDTH_8_MHZ: + case 8000000: buf[1] |= (2 << 2); break; default: - deb_info("%s: invalid bandwidth\n", __func__); - buf[1] |= (2 << 2); /* cannot auto-detect BW, try 8 MHz */ - } - - /* program */ - for (i = 0; i < sizeof(buf); i++) { - ret = af9013_write_reg(state, 0xd3c0 + i, buf[i]); - if (ret) - break; + dbg("%s: invalid bandwidth_hz", __func__); + ret = -EINVAL; + goto err; } - return ret; -} - -static int af9013_reset(struct af9013_state *state, u8 sleep) -{ - int ret; - u8 tmp, i; - deb_info("%s\n", __func__); - - /* enable OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 1); - if (ret) - goto error; - - /* start reset mechanism */ - ret = af9013_write_reg(state, 0xaeff, 1); + ret = af9013_wr_regs(state, 0xd3c0, buf, 3); if (ret) - goto error; + goto err; - /* reset is done when bit 1 is set */ - for (i = 0; i < 150; i++) { - ret = af9013_read_reg_bits(state, 0xd417, 1, 1, &tmp); - if (ret) - goto error; - if (tmp) - break; /* reset done */ - msleep(10); - } - if (!tmp) - return -ETIMEDOUT; - - /* don't clear reset when going to sleep */ - if (!sleep) { - /* clear OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); + if (auto_mode) { + /* clear easy mode flag */ + ret = af9013_wr_reg(state, 0xaefd, 0); if (ret) - goto error; - - /* disable OFDM reset */ - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); - } -error: - return ret; -} - -static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) -{ - int ret; - deb_info("%s: onoff:%d\n", __func__, onoff); + goto err; - if (onoff) { - /* power on */ - ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 0); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd417, 1, 1, 0); - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd417, 4, 1, 0); + dbg("%s: auto params", __func__); } else { - /* power off */ - ret = af9013_reset(state, 1); + /* set easy mode flag */ + ret = af9013_wr_reg(state, 0xaefd, 1); if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd73a, 3, 1, 1); - } -error: - return ret; -} - -static int af9013_lock_led(struct af9013_state *state, u8 onoff) -{ - deb_info("%s: onoff:%d\n", __func__, onoff); - - return af9013_write_reg_bits(state, 0xd730, 0, 1, onoff); -} - -static int af9013_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 auto_mode; /* auto set TPS */ + goto err; - deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, - params->u.ofdm.bandwidth); - - state->frequency = params->frequency; - - /* program tuner */ - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); - - /* program CFOE coefficients */ - ret = af9013_set_coeff(state, params->u.ofdm.bandwidth); - if (ret) - goto error; - - /* program frequency control */ - ret = af9013_set_freq_ctrl(state, params->u.ofdm.bandwidth); - if (ret) - goto error; - - /* clear TPS lock flag (inverted flag) */ - ret = af9013_write_reg_bits(state, 0xd330, 3, 1, 1); - if (ret) - goto error; - - /* clear MPEG2 lock flag */ - ret = af9013_write_reg_bits(state, 0xd507, 6, 1, 0); - if (ret) - goto error; - - /* empty channel function */ - ret = af9013_write_reg_bits(state, 0x9bfe, 0, 1, 0); - if (ret) - goto error; - - /* empty DVB-T channel function */ - ret = af9013_write_reg_bits(state, 0x9bc2, 0, 1, 0); - if (ret) - goto error; - - /* program TPS and bandwidth, check if auto mode needed */ - ret = af9013_set_ofdm_params(state, ¶ms->u.ofdm, &auto_mode); - if (ret) - goto error; - - if (auto_mode) { - /* clear easy mode flag */ - ret = af9013_write_reg(state, 0xaefd, 0); - deb_info("%s: auto TPS\n", __func__); - } else { - /* set easy mode flag */ - ret = af9013_write_reg(state, 0xaefd, 1); + ret = af9013_wr_reg(state, 0xaefe, 0); if (ret) - goto error; - ret = af9013_write_reg(state, 0xaefe, 0); - deb_info("%s: manual TPS\n", __func__); + goto err; + + dbg("%s: manual params", __func__); } - if (ret) - goto error; - /* everything is set, lets try to receive channel - OFSM GO! */ - ret = af9013_write_reg(state, 0xffff, 0); + /* tune */ + ret = af9013_wr_reg(state, 0xffff, 0); if (ret) - goto error; + goto err; + + state->bandwidth_hz = c->bandwidth_hz; + state->set_frontend_jiffies = jiffies; + state->first_tune = false; -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int af9013_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct af9013_state *state = fe->demodulator_priv; int ret; - u8 i, buf[3]; - deb_info("%s\n", __func__); + u8 buf[3]; - /* read TPS registers */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd3c0 + i, &buf[i]); - if (ret) - goto error; - } + dbg("%s", __func__); + + ret = af9013_rd_regs(state, 0xd3c0, buf, 3); + if (ret) + goto err; switch ((buf[1] >> 6) & 3) { case 0: - p->u.ofdm.constellation = QPSK; + c->modulation = QPSK; break; case 1: - p->u.ofdm.constellation = QAM_16; + c->modulation = QAM_16; break; case 2: - p->u.ofdm.constellation = QAM_64; + c->modulation = QAM_64; break; } switch ((buf[0] >> 0) & 3) { case 0: - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + c->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: - p->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + c->transmission_mode = TRANSMISSION_MODE_8K; } switch ((buf[0] >> 2) & 3) { case 0: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + c->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + c->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - p->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + c->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((buf[0] >> 4) & 7) { case 0: - p->u.ofdm.hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; break; case 1: - p->u.ofdm.hierarchy_information = HIERARCHY_1; + c->hierarchy = HIERARCHY_1; break; case 2: - p->u.ofdm.hierarchy_information = HIERARCHY_2; + c->hierarchy = HIERARCHY_2; break; case 3: - p->u.ofdm.hierarchy_information = HIERARCHY_4; + c->hierarchy = HIERARCHY_4; break; } switch ((buf[2] >> 0) & 7) { case 0: - p->u.ofdm.code_rate_HP = FEC_1_2; + c->code_rate_HP = FEC_1_2; break; case 1: - p->u.ofdm.code_rate_HP = FEC_2_3; + c->code_rate_HP = FEC_2_3; break; case 2: - p->u.ofdm.code_rate_HP = FEC_3_4; + c->code_rate_HP = FEC_3_4; break; case 3: - p->u.ofdm.code_rate_HP = FEC_5_6; + c->code_rate_HP = FEC_5_6; break; case 4: - p->u.ofdm.code_rate_HP = FEC_7_8; + c->code_rate_HP = FEC_7_8; break; } switch ((buf[2] >> 3) & 7) { case 0: - p->u.ofdm.code_rate_LP = FEC_1_2; + c->code_rate_LP = FEC_1_2; break; case 1: - p->u.ofdm.code_rate_LP = FEC_2_3; + c->code_rate_LP = FEC_2_3; break; case 2: - p->u.ofdm.code_rate_LP = FEC_3_4; + c->code_rate_LP = FEC_3_4; break; case 3: - p->u.ofdm.code_rate_LP = FEC_5_6; + c->code_rate_LP = FEC_5_6; break; case 4: - p->u.ofdm.code_rate_LP = FEC_7_8; + c->code_rate_LP = FEC_7_8; break; } switch ((buf[1] >> 2) & 3) { case 0: - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + c->bandwidth_hz = 6000000; break; case 1: - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + c->bandwidth_hz = 7000000; break; case 2: - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + c->bandwidth_hz = 8000000; break; } - p->inversion = INVERSION_AUTO; - p->frequency = state->frequency; - -error: return ret; -} - -static int af9013_update_ber_unc(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - u8 buf[3], i; - u32 error_bit_count = 0; - u32 total_bit_count = 0; - u32 abort_packet_count = 0; - - state->ber = 0; - - /* check if error bit count is ready */ - ret = af9013_read_reg_bits(state, 0xd391, 4, 1, &buf[0]); - if (ret) - goto error; - if (!buf[0]) - goto exit; - - /* get RSD packet abort count */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0xd38a + i, &buf[i]); - if (ret) - goto error; - } - abort_packet_count = (buf[1] << 8) + buf[0]; - - /* get error bit count */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd387 + i, &buf[i]); - if (ret) - goto error; - } - error_bit_count = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - error_bit_count = error_bit_count - abort_packet_count * 8 * 8; - - /* get used RSD counting period (10000 RSD packets used) */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0xd385 + i, &buf[i]); - if (ret) - goto error; - } - total_bit_count = (buf[1] << 8) + buf[0]; - total_bit_count = total_bit_count - abort_packet_count; - total_bit_count = total_bit_count * 204 * 8; - - if (total_bit_count) - state->ber = error_bit_count * 1000000000 / total_bit_count; - - state->ucblocks += abort_packet_count; - - deb_info("%s: err bits:%d total bits:%d abort count:%d\n", __func__, - error_bit_count, total_bit_count, abort_packet_count); - - /* set BER counting range */ - ret = af9013_write_reg(state, 0xd385, 10000 & 0xff); - if (ret) - goto error; - ret = af9013_write_reg(state, 0xd386, 10000 >> 8); - if (ret) - goto error; - /* reset and start BER counter */ - ret = af9013_write_reg_bits(state, 0xd391, 4, 1, 1); - if (ret) - goto error; - -exit: -error: +err: + dbg("%s: failed=%d", __func__, ret); return ret; } -static int af9013_update_snr(struct dvb_frontend *fe) +static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct af9013_state *state = fe->demodulator_priv; int ret; - u8 buf[3], i, len; - u32 quant = 0; - struct snr_table *uninitialized_var(snr_table); - - /* check if quantizer ready (for snr) */ - ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]); - if (ret) - goto error; - if (buf[0]) { - /* quantizer ready - read it */ - for (i = 0; i < 3; i++) { - ret = af9013_read_reg(state, 0xd2e3 + i, &buf[i]); - if (ret) - goto error; - } - quant = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - - /* read current constellation */ - ret = af9013_read_reg(state, 0xd3c1, &buf[0]); - if (ret) - goto error; - - switch ((buf[0] >> 6) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_table); - snr_table = qpsk_snr_table; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_table); - snr_table = qam16_snr_table; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_table); - snr_table = qam64_snr_table; - break; - default: - len = 0; - break; - } - - if (len) { - for (i = 0; i < len; i++) { - if (quant < snr_table[i].val) { - state->snr = snr_table[i].snr * 10; - break; - } - } - } - - /* set quantizer super frame count */ - ret = af9013_write_reg(state, 0xd2e2, 1); - if (ret) - goto error; - - /* check quantizer availability */ - for (i = 0; i < 10; i++) { - msleep(10); - ret = af9013_read_reg_bits(state, 0xd2e6, 0, 1, - &buf[0]); - if (ret) - goto error; - if (!buf[0]) - break; - } - - /* reset quantizer */ - ret = af9013_write_reg_bits(state, 0xd2e1, 3, 1, 1); - if (ret) - goto error; - } - -error: - return ret; -} - -static int af9013_update_signal_strength(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret = 0; - u8 rf_gain, if_gain; - int signal_strength; - - deb_info("%s\n", __func__); + u8 tmp; - if (state->signal_strength_en) { - ret = af9013_read_reg(state, 0xd07c, &rf_gain); - if (ret) - goto error; - ret = af9013_read_reg(state, 0xd07d, &if_gain); - if (ret) - goto error; - signal_strength = (0xffff / \ - (9 * (state->rf_50 + state->if_50) - \ - 11 * (state->rf_80 + state->if_80))) * \ - (10 * (rf_gain + if_gain) - \ - 11 * (state->rf_80 + state->if_80)); - if (signal_strength < 0) - signal_strength = 0; - else if (signal_strength > 0xffff) - signal_strength = 0xffff; - - state->signal_strength = signal_strength; + /* + * Return status from the cache if it is younger than 2000ms with the + * exception of last tune is done during 4000ms. + */ + if (time_is_after_jiffies( + state->read_status_jiffies + msecs_to_jiffies(2000)) && + time_is_before_jiffies( + state->set_frontend_jiffies + msecs_to_jiffies(4000)) + ) { + *status = state->fe_status; + return 0; } else { - state->signal_strength = 0; + *status = 0; } -error: - return ret; -} - -static int af9013_update_statistics(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - - if (time_before(jiffies, state->next_statistics_check)) - return 0; - - /* set minimum statistic update interval */ - state->next_statistics_check = jiffies + msecs_to_jiffies(1200); - - ret = af9013_update_signal_strength(fe); - if (ret) - goto error; - ret = af9013_update_snr(fe); - if (ret) - goto error; - ret = af9013_update_ber_unc(fe); - if (ret) - goto error; - -error: - return ret; -} - -static int af9013_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) -{ - fesettings->min_delay_ms = 800; - fesettings->step_size = 0; - fesettings->max_drift = 0; - - return 0; -} - -static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret = 0; - u8 tmp; - *status = 0; - /* MPEG2 lock */ - ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp); + ret = af9013_rd_reg_bits(state, 0xd507, 6, 1, &tmp); if (ret) - goto error; + goto err; + if (tmp) *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; if (!*status) { /* TPS lock */ - ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp); + ret = af9013_rd_reg_bits(state, 0xd330, 3, 1, &tmp); if (ret) - goto error; + goto err; + if (tmp) *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI; } - if (!*status) { - /* CFO lock */ - ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - } - - if (!*status) { - /* SFOE lock */ - ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; - } + state->fe_status = *status; + state->read_status_jiffies = jiffies; - if (!*status) { - /* AGC lock */ - ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp); - if (ret) - goto error; - if (tmp) - *status |= FE_HAS_SIGNAL; - } - - ret = af9013_update_statistics(fe); - -error: + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } - -static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) +static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *ber = state->ber; - return ret; + *snr = state->snr; + return 0; } static int af9013_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); *strength = state->signal_strength; - return ret; + return 0; } -static int af9013_read_snr(struct dvb_frontend *fe, u16 *snr) +static int af9013_read_ber(struct dvb_frontend *fe, u32 *ber) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); - *snr = state->snr; - return ret; + *ber = state->ber; + return 0; } static int af9013_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct af9013_state *state = fe->demodulator_priv; - int ret; - ret = af9013_update_statistics(fe); *ucblocks = state->ucblocks; - return ret; -} - -static int af9013_sleep(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - int ret; - deb_info("%s\n", __func__); - - ret = af9013_lock_led(state, 0); - if (ret) - goto error; - - ret = af9013_power_ctrl(state, 0); -error: - return ret; + return 0; } static int af9013_init(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; int ret, i, len; - u8 tmp0, tmp1; - struct regdesc *init; - deb_info("%s\n", __func__); + u8 buf[3], tmp; + u32 adc_cw; + const struct af9013_reg_bit *init; - /* reset OFDM */ - ret = af9013_reset(state, 0); - if (ret) - goto error; + dbg("%s", __func__); /* power on */ ret = af9013_power_ctrl(state, 1); if (ret) - goto error; + goto err; /* enable ADC */ - ret = af9013_write_reg(state, 0xd73a, 0xa4); + ret = af9013_wr_reg(state, 0xd73a, 0xa4); if (ret) - goto error; + goto err; /* write API version to firmware */ - for (i = 0; i < sizeof(state->config.api_version); i++) { - ret = af9013_write_reg(state, 0x9bf2 + i, - state->config.api_version[i]); - if (ret) - goto error; - } + ret = af9013_wr_regs(state, 0x9bf2, state->config.api_version, 4); + if (ret) + goto err; /* program ADC control */ - ret = af9013_set_adc_ctrl(state); + switch (state->config.clock) { + case 28800000: /* 28.800 MHz */ + tmp = 0; + break; + case 20480000: /* 20.480 MHz */ + tmp = 1; + break; + case 28000000: /* 28.000 MHz */ + tmp = 2; + break; + case 25000000: /* 25.000 MHz */ + tmp = 3; + break; + default: + err("invalid clock"); + return -EINVAL; + } + + adc_cw = af913_div(state->config.clock, 1000000ul, 19); + buf[0] = (adc_cw >> 0) & 0xff; + buf[1] = (adc_cw >> 8) & 0xff; + buf[2] = (adc_cw >> 16) & 0xff; + + ret = af9013_wr_regs(state, 0xd180, buf, 3); + if (ret) + goto err; + + ret = af9013_wr_reg_bits(state, 0x9bd2, 0, 4, tmp); if (ret) - goto error; + goto err; /* set I2C master clock */ - ret = af9013_write_reg(state, 0xd416, 0x14); + ret = af9013_wr_reg(state, 0xd416, 0x14); if (ret) - goto error; + goto err; /* set 16 embx */ - ret = af9013_write_reg_bits(state, 0xd700, 1, 1, 1); + ret = af9013_wr_reg_bits(state, 0xd700, 1, 1, 1); if (ret) - goto error; + goto err; /* set no trigger */ - ret = af9013_write_reg_bits(state, 0xd700, 2, 1, 0); + ret = af9013_wr_reg_bits(state, 0xd700, 2, 1, 0); if (ret) - goto error; + goto err; /* set read-update bit for constellation */ - ret = af9013_write_reg_bits(state, 0xd371, 1, 1, 1); + ret = af9013_wr_reg_bits(state, 0xd371, 1, 1, 1); if (ret) - goto error; + goto err; - /* enable FEC monitor */ - ret = af9013_write_reg_bits(state, 0xd392, 1, 1, 1); + /* settings for mp2if */ + if (state->config.ts_mode == AF9013_TS_USB) { + /* AF9015 split PSB to 1.5k + 0.5k */ + ret = af9013_wr_reg_bits(state, 0xd50b, 2, 1, 1); + if (ret) + goto err; + } else { + /* AF9013 change the output bit to data7 */ + ret = af9013_wr_reg_bits(state, 0xd500, 3, 1, 1); + if (ret) + goto err; + + /* AF9013 set mpeg to full speed */ + ret = af9013_wr_reg_bits(state, 0xd502, 4, 1, 1); + if (ret) + goto err; + } + + ret = af9013_wr_reg_bits(state, 0xd520, 4, 1, 1); if (ret) - goto error; + goto err; /* load OFSM settings */ - deb_info("%s: load ofsm settings\n", __func__); + dbg("%s: load ofsm settings", __func__); len = ARRAY_SIZE(ofsm_init); init = ofsm_init; for (i = 0; i < len; i++) { - ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos, init[i].len, init[i].val); if (ret) - goto error; + goto err; } /* load tuner specific settings */ - deb_info("%s: load tuner specific settings\n", __func__); + dbg("%s: load tuner specific settings", __func__); switch (state->config.tuner) { case AF9013_TUNER_MXL5003D: len = ARRAY_SIZE(tuner_init_mxl5003d); @@ -1260,65 +1197,133 @@ static int af9013_init(struct dvb_frontend *fe) } for (i = 0; i < len; i++) { - ret = af9013_write_reg_bits(state, init[i].addr, init[i].pos, + ret = af9013_wr_reg_bits(state, init[i].addr, init[i].pos, init[i].len, init[i].val); if (ret) - goto error; + goto err; } - /* set TS mode */ - deb_info("%s: setting ts mode\n", __func__); - tmp0 = 0; /* parallel mode */ - tmp1 = 0; /* serial mode */ - switch (state->config.output_mode) { - case AF9013_OUTPUT_MODE_PARALLEL: - tmp0 = 1; - break; - case AF9013_OUTPUT_MODE_SERIAL: - tmp1 = 1; - break; - case AF9013_OUTPUT_MODE_USB: - /* usb mode for AF9015 */ - default: - break; - } - ret = af9013_write_reg_bits(state, 0xd500, 1, 1, tmp0); /* parallel */ + /* TS mode */ + ret = af9013_wr_reg_bits(state, 0xd500, 1, 2, state->config.ts_mode); if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd500, 2, 1, tmp1); /* serial */ - if (ret) - goto error; + goto err; /* enable lock led */ - ret = af9013_lock_led(state, 1); + ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 1); if (ret) - goto error; + goto err; - /* read values needed for signal strength calculation */ - ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, - &state->signal_strength_en); - if (ret) - goto error; + /* check if we support signal strength */ + if (!state->signal_strength_en) { + ret = af9013_rd_reg_bits(state, 0x9bee, 0, 1, + &state->signal_strength_en); + if (ret) + goto err; + } - if (state->signal_strength_en) { - ret = af9013_read_reg(state, 0x9bbd, &state->rf_50); + /* read values needed for signal strength calculation */ + if (state->signal_strength_en && !state->rf_50) { + ret = af9013_rd_reg(state, 0x9bbd, &state->rf_50); if (ret) - goto error; - ret = af9013_read_reg(state, 0x9bd0, &state->rf_80); + goto err; + + ret = af9013_rd_reg(state, 0x9bd0, &state->rf_80); if (ret) - goto error; - ret = af9013_read_reg(state, 0x9be2, &state->if_50); + goto err; + + ret = af9013_rd_reg(state, 0x9be2, &state->if_50); if (ret) - goto error; - ret = af9013_read_reg(state, 0x9be4, &state->if_80); + goto err; + + ret = af9013_rd_reg(state, 0x9be4, &state->if_80); if (ret) - goto error; + goto err; } -error: + /* SNR */ + ret = af9013_wr_reg(state, 0xd2e2, 1); + if (ret) + goto err; + + /* BER / UCB */ + buf[0] = (10000 >> 0) & 0xff; + buf[1] = (10000 >> 8) & 0xff; + ret = af9013_wr_regs(state, 0xd385, buf, 2); + if (ret) + goto err; + + /* enable FEC monitor */ + ret = af9013_wr_reg_bits(state, 0xd392, 1, 1, 1); + if (ret) + goto err; + + state->first_tune = true; + schedule_delayed_work(&state->statistics_work, msecs_to_jiffies(400)); + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); return ret; } +static int af9013_sleep(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + int ret; + + dbg("%s", __func__); + + /* stop statistics polling */ + cancel_delayed_work_sync(&state->statistics_work); + + /* disable lock led */ + ret = af9013_wr_reg_bits(state, 0xd730, 0, 1, 0); + if (ret) + goto err; + + /* power off */ + ret = af9013_power_ctrl(state, 0); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret; + struct af9013_state *state = fe->demodulator_priv; + + dbg("%s: enable=%d", __func__, enable); + + /* gate already open or close */ + if (state->i2c_gate_state == enable) + return 0; + + if (state->config.ts_mode == AF9013_TS_USB) + ret = af9013_wr_reg_bits(state, 0xd417, 3, 1, enable); + else + ret = af9013_wr_reg_bits(state, 0xd607, 2, 1, enable); + if (ret) + goto err; + + state->i2c_gate_state = enable; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static void af9013_release(struct dvb_frontend *fe) +{ + struct af9013_state *state = fe->demodulator_priv; + kfree(state); +} + static struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) @@ -1332,11 +1337,11 @@ static int af9013_download_firmware(struct af9013_state *state) msleep(100); /* check whether firmware is already running */ - ret = af9013_read_reg(state, 0x98be, &val); + ret = af9013_rd_reg(state, 0x98be, &val); if (ret) - goto error; + goto err; else - deb_info("%s: firmware status:%02x\n", __func__, val); + dbg("%s: firmware status=%02x", __func__, val); if (val == 0x0c) /* fw is running, no need for download */ goto exit; @@ -1351,7 +1356,7 @@ static int af9013_download_firmware(struct af9013_state *state) "Please see linux/Documentation/dvb/ for more details" \ " on firmware-problems. (%d)", fw_file, ret); - goto error; + goto err; } info("downloading firmware from file '%s'", fw_file); @@ -1369,7 +1374,7 @@ static int af9013_download_firmware(struct af9013_state *state) ret = af9013_write_ofsm_regs(state, 0x50fc, fw_params, sizeof(fw_params)); if (ret) - goto error_release; + goto err_release; #define FW_ADDR 0x5100 /* firmware start address */ #define LEN_MAX 16 /* max packet size */ @@ -1383,24 +1388,24 @@ static int af9013_download_firmware(struct af9013_state *state) (u8 *) &fw->data[fw->size - remaining], len); if (ret) { err("firmware download failed:%d", ret); - goto error_release; + goto err_release; } } /* request boot firmware */ - ret = af9013_write_reg(state, 0xe205, 1); + ret = af9013_wr_reg(state, 0xe205, 1); if (ret) - goto error_release; + goto err_release; for (i = 0; i < 15; i++) { msleep(100); /* check firmware status */ - ret = af9013_read_reg(state, 0x98be, &val); + ret = af9013_rd_reg(state, 0x98be, &val); if (ret) - goto error_release; + goto err_release; - deb_info("%s: firmware status:%02x\n", __func__, val); + dbg("%s: firmware status=%02x", __func__, val); if (val == 0x0c || val == 0x04) /* success or fail */ break; @@ -1408,43 +1413,21 @@ static int af9013_download_firmware(struct af9013_state *state) if (val == 0x04) { err("firmware did not run"); - ret = -1; + ret = -ENODEV; } else if (val != 0x0c) { err("firmware boot timeout"); - ret = -1; + ret = -ENODEV; } -error_release: +err_release: release_firmware(fw); -error: +err: exit: if (!ret) info("found a '%s' in warm state.", af9013_ops.info.name); return ret; } -static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct af9013_state *state = fe->demodulator_priv; - deb_info("%s: enable:%d\n", __func__, enable); - - if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) - ret = af9013_write_reg_bits(state, 0xd417, 3, 1, enable); - else - ret = af9013_write_reg_bits(state, 0xd607, 2, 1, enable); - - return ret; -} - -static void af9013_release(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - kfree(state); -} - -static struct dvb_frontend_ops af9013_ops; - struct dvb_frontend *af9013_attach(const struct af9013_config *config, struct i2c_adapter *i2c) { @@ -1455,91 +1438,65 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL); if (state == NULL) - goto error; + goto err; /* setup the state */ state->i2c = i2c; memcpy(&state->config, config, sizeof(struct af9013_config)); /* download firmware */ - if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { + if (state->config.ts_mode != AF9013_TS_USB) { ret = af9013_download_firmware(state); if (ret) - goto error; + goto err; } /* firmware version */ - for (i = 0; i < 4; i++) { - ret = af9013_read_reg(state, 0x5103 + i, &buf[i]); - if (ret) - goto error; - } - info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); - - /* chip version */ - ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); + ret = af9013_rd_regs(state, 0x5103, buf, 4); if (ret) - goto error; + goto err; - /* ROM version */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0x116b + i, &buf[i]); - if (ret) - goto error; - } - deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, - buf[2], buf[0], buf[1]); - - /* settings for mp2if */ - if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { - /* AF9015 split PSB to 1.5k + 0.5k */ - ret = af9013_write_reg_bits(state, 0xd50b, 2, 1, 1); - } else { - /* AF9013 change the output bit to data7 */ - ret = af9013_write_reg_bits(state, 0xd500, 3, 1, 1); - if (ret) - goto error; - /* AF9013 set mpeg to full speed */ - ret = af9013_write_reg_bits(state, 0xd502, 4, 1, 1); - } - if (ret) - goto error; - ret = af9013_write_reg_bits(state, 0xd520, 4, 1, 1); - if (ret) - goto error; + info("firmware version %d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); /* set GPIOs */ for (i = 0; i < sizeof(state->config.gpio); i++) { ret = af9013_set_gpio(state, i, state->config.gpio[i]); if (ret) - goto error; + goto err; } /* create dvb_frontend */ - memcpy(&state->frontend.ops, &af9013_ops, + memcpy(&state->fe.ops, &af9013_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; + state->fe.demodulator_priv = state; + + INIT_DELAYED_WORK(&state->statistics_work, af9013_statistics_work); - return &state->frontend; -error: + return &state->fe; +err: kfree(state); return NULL; } EXPORT_SYMBOL(af9013_attach); static struct dvb_frontend_ops af9013_ops = { + .delsys = { SYS_DVBT }, .info = { - .name = "Afatech AF9013 DVB-T", - .type = FE_OFDM, + .name = "Afatech AF9013", .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 250000, .frequency_tolerance = 0, - .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_64 | FE_CAN_QAM_AUTO | + .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_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | @@ -1548,24 +1505,22 @@ static struct dvb_frontend_ops af9013_ops = { }, .release = af9013_release, + .init = af9013_init, .sleep = af9013_sleep, - .i2c_gate_ctrl = af9013_i2c_gate_ctrl, + .get_tune_settings = af9013_get_tune_settings, .set_frontend = af9013_set_frontend, .get_frontend = af9013_get_frontend, - .get_tune_settings = af9013_get_tune_settings, - .read_status = af9013_read_status, - .read_ber = af9013_read_ber, - .read_signal_strength = af9013_read_signal_strength, .read_snr = af9013_read_snr, + .read_signal_strength = af9013_read_signal_strength, + .read_ber = af9013_read_ber, .read_ucblocks = af9013_read_ucblocks, -}; -module_param_named(debug, af9013_debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + .i2c_gate_ctrl = af9013_i2c_gate_ctrl, +}; MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Afatech AF9013 DVB-T demodulator driver"); diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h index e53d873f7555..b973fc5a0384 100644 --- a/drivers/media/dvb/frontends/af9013.h +++ b/drivers/media/dvb/frontends/af9013.h @@ -2,6 +2,7 @@ * Afatech AF9013 demodulator driver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * @@ -21,33 +22,11 @@ * */ -#ifndef _AF9013_H_ -#define _AF9013_H_ +#ifndef AF9013_H +#define AF9013_H #include <linux/dvb/frontend.h> -enum af9013_ts_mode { - AF9013_OUTPUT_MODE_PARALLEL, - AF9013_OUTPUT_MODE_SERIAL, - AF9013_OUTPUT_MODE_USB, /* only for AF9015 */ -}; - -enum af9013_tuner { - AF9013_TUNER_MXL5003D = 3, /* MaxLinear */ - AF9013_TUNER_MXL5005D = 13, /* MaxLinear */ - AF9013_TUNER_MXL5005R = 30, /* MaxLinear */ - AF9013_TUNER_ENV77H11D5 = 129, /* Panasonic */ - AF9013_TUNER_MT2060 = 130, /* Microtune */ - AF9013_TUNER_MC44S803 = 133, /* Freescale */ - AF9013_TUNER_QT1010 = 134, /* Quantek */ - AF9013_TUNER_UNKNOWN = 140, /* for can tuners ? */ - AF9013_TUNER_MT2060_2 = 147, /* Microtune */ - AF9013_TUNER_TDA18271 = 156, /* NXP */ - AF9013_TUNER_QT1010A = 162, /* Quantek */ - AF9013_TUNER_MXL5007T = 177, /* MaxLinear */ - AF9013_TUNER_TDA18218 = 179, /* NXP */ -}; - /* AF9013/5 GPIOs (mostly guessed) demod#1-gpio#0 - set demod#2 i2c-addr for dual devices demod#1-gpio#1 - xtal setting (?) @@ -55,44 +34,74 @@ enum af9013_tuner { demod#2-gpio#0 - tuner#2 demod#2-gpio#1 - xtal setting (?) */ + +struct af9013_config { + /* + * I2C address + */ + u8 i2c_addr; + + /* + * clock + * 20480000, 25000000, 28000000, 28800000 + */ + u32 clock; + + /* + * tuner + */ +#define AF9013_TUNER_MXL5003D 3 /* MaxLinear */ +#define AF9013_TUNER_MXL5005D 13 /* MaxLinear */ +#define AF9013_TUNER_MXL5005R 30 /* MaxLinear */ +#define AF9013_TUNER_ENV77H11D5 129 /* Panasonic */ +#define AF9013_TUNER_MT2060 130 /* Microtune */ +#define AF9013_TUNER_MC44S803 133 /* Freescale */ +#define AF9013_TUNER_QT1010 134 /* Quantek */ +#define AF9013_TUNER_UNKNOWN 140 /* for can tuners ? */ +#define AF9013_TUNER_MT2060_2 147 /* Microtune */ +#define AF9013_TUNER_TDA18271 156 /* NXP */ +#define AF9013_TUNER_QT1010A 162 /* Quantek */ +#define AF9013_TUNER_MXL5007T 177 /* MaxLinear */ +#define AF9013_TUNER_TDA18218 179 /* NXP */ + u8 tuner; + + /* + * IF frequency + */ + u32 if_frequency; + + /* + * TS settings + */ +#define AF9013_TS_USB 0 +#define AF9013_TS_PARALLEL 1 +#define AF9013_TS_SERIAL 2 + u8 ts_mode:2; + + /* + * input spectrum inversion + */ + bool spec_inv; + + /* + * firmware API version + */ + u8 api_version[4]; + + /* + * GPIOs + */ #define AF9013_GPIO_ON (1 << 0) #define AF9013_GPIO_EN (1 << 1) #define AF9013_GPIO_O (1 << 2) #define AF9013_GPIO_I (1 << 3) - #define AF9013_GPIO_LO (AF9013_GPIO_ON|AF9013_GPIO_EN) #define AF9013_GPIO_HI (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) - #define AF9013_GPIO_TUNER_ON (AF9013_GPIO_ON|AF9013_GPIO_EN) #define AF9013_GPIO_TUNER_OFF (AF9013_GPIO_ON|AF9013_GPIO_EN|AF9013_GPIO_O) - -struct af9013_config { - /* demodulator's I2C address */ - u8 demod_address; - - /* frequencies in kHz */ - u32 adc_clock; - - /* tuner ID */ - u8 tuner; - - /* tuner IF */ - u16 tuner_if; - - /* TS data output mode */ - u8 output_mode:2; - - /* RF spectrum inversion */ - u8 rf_spec_inv:1; - - /* API version */ - u8 api_version[4]; - - /* GPIOs */ u8 gpio[4]; }; - #if defined(CONFIG_DVB_AF9013) || \ (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, @@ -106,4 +115,4 @@ const struct af9013_config *config, struct i2c_adapter *i2c) } #endif /* CONFIG_DVB_AF9013 */ -#endif /* _AF9013_H_ */ +#endif /* AF9013_H */ diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h index e00b2a4a2db6..fa848af6e9b4 100644 --- a/drivers/media/dvb/frontends/af9013_priv.h +++ b/drivers/media/dvb/frontends/af9013_priv.h @@ -2,6 +2,7 @@ * Afatech AF9013 demodulator driver * * Copyright (C) 2007 Antti Palosaari <crope@iki.fi> + * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> * * Thanks to Afatech who kindly provided information. * @@ -21,24 +22,19 @@ * */ -#ifndef _AF9013_PRIV_ -#define _AF9013_PRIV_ +#ifndef AF9013_PRIV_H +#define AF9013_PRIV_H -#define LOG_PREFIX "af9013" -extern int af9013_debug; - -#define dprintk(var, level, args...) \ - do { if ((var & level)) printk(args); } while (0) +#include "dvb_frontend.h" +#include "af9013.h" +#include <linux/firmware.h> -#define debug_dump(b, l, func) {\ - int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) \ - func("%02x ", b[loop_]); \ - func("\n");\ -} - -#define deb_info(args...) dprintk(af9013_debug, 0x01, args) +#define LOG_PREFIX "af9013" +#undef dbg +#define dbg(f, arg...) \ + if (af9013_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) #undef err #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) #undef info @@ -48,70 +44,71 @@ extern int af9013_debug; #define AF9013_DEFAULT_FIRMWARE "dvb-fe-af9013.fw" -struct regdesc { +struct af9013_reg_bit { u16 addr; u8 pos:4; u8 len:4; u8 val; }; -struct snr_table { +struct af9013_snr { u32 val; u8 snr; }; -struct coeff { - u32 adc_clock; - fe_bandwidth_t bw; +struct af9013_coeff { + u32 clock; + u32 bandwidth_hz; u8 val[24]; }; /* pre-calculated coeff lookup table */ -static struct coeff coeff_table[] = { +static const struct af9013_coeff coeff_lut[] = { /* 28.800 MHz */ - { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14, + { 28800000, 8000000, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14, 0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a, 0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } }, - { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71, + { 28800000, 7000000, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71, 0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38, 0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } }, - { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf, + { 28800000, 6000000, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf, 0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7, 0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } }, /* 20.480 MHz */ - { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24, + { 20480000, 8000000, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24, 0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92, 0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } }, - { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40, + { 20480000, 7000000, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40, 0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } }, - { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b, + { 20480000, 6000000, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b, 0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d, 0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } }, /* 28.000 MHz */ - { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39, + { 28000000, 8000000, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39, 0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f, 0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } }, - { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92, + { 28000000, 7000000, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92, 0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49, 0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } }, - { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb, + { 28000000, 6000000, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb, 0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63, 0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } }, /* 25.000 MHz */ - { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9, + { 25000000, 8000000, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9, 0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e, 0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } }, - { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e, + { 25000000, 7000000, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e, 0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7, 0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } }, - { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63, + { 25000000, 6000000, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63, 0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f, 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } }, }; /* QPSK SNR lookup table */ -static struct snr_table qpsk_snr_table[] = { +static const struct af9013_snr qpsk_snr_lut[] = { + { 0x000000, 0 }, { 0x0b4771, 0 }, { 0x0c1aed, 1 }, { 0x0d0d27, 2 }, @@ -131,7 +128,8 @@ static struct snr_table qpsk_snr_table[] = { }; /* QAM16 SNR lookup table */ -static struct snr_table qam16_snr_table[] = { +static const struct af9013_snr qam16_snr_lut[] = { + { 0x000000, 0 }, { 0x05eb62, 5 }, { 0x05fecf, 6 }, { 0x060b80, 7 }, @@ -151,7 +149,8 @@ static struct snr_table qam16_snr_table[] = { }; /* QAM64 SNR lookup table */ -static struct snr_table qam64_snr_table[] = { +static const struct af9013_snr qam64_snr_lut[] = { + { 0x000000, 0 }, { 0x03109b, 12 }, { 0x0310d4, 13 }, { 0x031920, 14 }, @@ -170,7 +169,7 @@ static struct snr_table qam64_snr_table[] = { { 0xffffff, 27 }, }; -static struct regdesc ofsm_init[] = { +static const struct af9013_reg_bit ofsm_init[] = { { 0xd73a, 0, 8, 0xa1 }, { 0xd73b, 0, 8, 0x1f }, { 0xd73c, 4, 4, 0x0a }, @@ -252,7 +251,7 @@ static struct regdesc ofsm_init[] = { /* Panasonic ENV77H11D5 tuner init AF9013_TUNER_ENV77H11D5 = 129 */ -static struct regdesc tuner_init_env77h11d5[] = { +static const struct af9013_reg_bit tuner_init_env77h11d5[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x03 }, { 0x9bbe, 0, 8, 0x01 }, @@ -318,7 +317,7 @@ static struct regdesc tuner_init_env77h11d5[] = { /* Microtune MT2060 tuner init AF9013_TUNER_MT2060 = 130 */ -static struct regdesc tuner_init_mt2060[] = { +static const struct af9013_reg_bit tuner_init_mt2060[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x07 }, { 0xd1a0, 1, 1, 0x01 }, @@ -395,7 +394,7 @@ static struct regdesc tuner_init_mt2060[] = { /* Microtune MT2060 tuner init AF9013_TUNER_MT2060_2 = 147 */ -static struct regdesc tuner_init_mt2060_2[] = { +static const struct af9013_reg_bit tuner_init_mt2060_2[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x06 }, { 0x9bbe, 0, 8, 0x01 }, @@ -462,7 +461,7 @@ static struct regdesc tuner_init_mt2060_2[] = { /* MaxLinear MXL5003 tuner init AF9013_TUNER_MXL5003D = 3 */ -static struct regdesc tuner_init_mxl5003d[] = { +static const struct af9013_reg_bit tuner_init_mxl5003d[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x09 }, { 0xd1a0, 1, 1, 0x01 }, @@ -534,7 +533,7 @@ static struct regdesc tuner_init_mxl5003d[] = { AF9013_TUNER_MXL5005D = 13 AF9013_TUNER_MXL5005R = 30 AF9013_TUNER_MXL5007T = 177 */ -static struct regdesc tuner_init_mxl5005[] = { +static const struct af9013_reg_bit tuner_init_mxl5005[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x07 }, { 0xd1a0, 1, 1, 0x01 }, @@ -613,7 +612,7 @@ static struct regdesc tuner_init_mxl5005[] = { /* Quantek QT1010 tuner init AF9013_TUNER_QT1010 = 134 AF9013_TUNER_QT1010A = 162 */ -static struct regdesc tuner_init_qt1010[] = { +static const struct af9013_reg_bit tuner_init_qt1010[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x09 }, { 0xd1a0, 1, 1, 0x01 }, @@ -690,7 +689,7 @@ static struct regdesc tuner_init_qt1010[] = { /* Freescale MC44S803 tuner init AF9013_TUNER_MC44S803 = 133 */ -static struct regdesc tuner_init_mc44s803[] = { +static const struct af9013_reg_bit tuner_init_mc44s803[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x06 }, { 0xd1a0, 1, 1, 0x01 }, @@ -772,7 +771,7 @@ static struct regdesc tuner_init_mc44s803[] = { /* unknown, probably for tin can tuner, tuner init AF9013_TUNER_UNKNOWN = 140 */ -static struct regdesc tuner_init_unknown[] = { +static const struct af9013_reg_bit tuner_init_unknown[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x02 }, { 0xd1a0, 1, 1, 0x01 }, @@ -845,7 +844,7 @@ static struct regdesc tuner_init_unknown[] = { /* NXP TDA18271 & TDA18218 tuner init AF9013_TUNER_TDA18271 = 156 AF9013_TUNER_TDA18218 = 179 */ -static struct regdesc tuner_init_tda18271[] = { +static const struct af9013_reg_bit tuner_init_tda18271[] = { { 0x9bd5, 0, 8, 0x01 }, { 0x9bd6, 0, 8, 0x04 }, { 0xd1a0, 1, 1, 0x01 }, @@ -920,4 +919,4 @@ static struct regdesc tuner_init_tda18271[] = { { 0x9bee, 0, 1, 0x01 }, }; -#endif /* _AF9013_PRIV_ */ +#endif /* AF9013_PRIV_H */ diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c index 1539ea1f81ac..a2261ea2cf82 100644 --- a/drivers/media/dvb/frontends/atbm8830.c +++ b/drivers/media/dvb/frontends/atbm8830.c @@ -267,8 +267,7 @@ static void atbm8830_release(struct dvb_frontend *fe) kfree(state); } -static int atbm8830_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int atbm8830_set_fe(struct dvb_frontend *fe) { struct atbm_state *priv = fe->demodulator_priv; int i; @@ -279,7 +278,7 @@ static int atbm8830_set_fe(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -298,31 +297,31 @@ static int atbm8830_set_fe(struct dvb_frontend *fe, return 0; } -static int atbm8830_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int atbm8830_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; dprintk("%s\n", __func__); /* TODO: get real readings from device */ /* inversion status */ - fe_params->inversion = INVERSION_OFF; + c->inversion = INVERSION_OFF; /* bandwidth */ - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + c->bandwidth_hz = 8000000; - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.code_rate_LP = FEC_AUTO; + c->code_rate_HP = FEC_AUTO; + c->code_rate_LP = FEC_AUTO; - fe_params->u.ofdm.constellation = QAM_AUTO; + c->modulation = QAM_AUTO; /* transmission mode */ - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + c->transmission_mode = TRANSMISSION_MODE_AUTO; /* guard interval */ - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + c->guard_interval = GUARD_INTERVAL_AUTO; /* hierarchy */ - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; return 0; } @@ -429,9 +428,9 @@ static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } static struct dvb_frontend_ops atbm8830_ops = { + .delsys = { SYS_DMBTH }, .info = { .name = "AltoBeam ATBM8830/8831 DMB-TH", - .type = FE_OFDM, .frequency_min = 474000000, .frequency_max = 858000000, .frequency_stepsize = 10000, diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index 1d572940e243..c688b95df486 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c @@ -576,19 +576,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int au8522_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int au8522_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct au8522_state *state = fe->demodulator_priv; int ret = -EINVAL; - dprintk("%s(frequency=%d)\n", __func__, p->frequency); + dprintk("%s(frequency=%d)\n", __func__, c->frequency); - if ((state->current_frequency == p->frequency) && - (state->current_modulation == p->u.vsb.modulation)) + if ((state->current_frequency == c->frequency) && + (state->current_modulation == c->modulation)) return 0; - au8522_enable_modulation(fe, p->u.vsb.modulation); + au8522_enable_modulation(fe, c->modulation); /* Allow the demod to settle */ msleep(100); @@ -596,7 +596,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - ret = fe->ops.tuner_ops.set_params(fe, p); + ret = fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -604,7 +604,7 @@ static int au8522_set_frontend(struct dvb_frontend *fe, if (ret < 0) return ret; - state->current_frequency = p->frequency; + state->current_frequency = c->frequency; return 0; } @@ -862,7 +862,36 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) static int au8522_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { - return au8522_read_snr(fe, signal_strength); + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + u16 snr; + u32 tmp; + int ret = au8522_read_snr(fe, &snr); + + *signal_strength = 0; + + if (0 == ret) { + /* The following calculation method was chosen + * purely for the sake of code re-use from the + * other demod drivers that use this method */ + + /* Convert from SNR in dB * 10 to 8.24 fixed-point */ + tmp = (snr * ((1 << 24) / 10)); + + /* Convert from 8.24 fixed-point to + * scale the range 0 - 35*2^24 into 0 - 65535*/ + if (tmp >= 8960 * 0x10000) + *signal_strength = 0xffff; + else + *signal_strength = tmp / 8960; + } + + return ret; } static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -882,13 +911,13 @@ static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber) return au8522_read_ucblocks(fe, ber); } -static int au8522_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int au8522_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct au8522_state *state = fe->demodulator_priv; - p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; + c->frequency = state->current_frequency; + c->modulation = state->current_modulation; return 0; } @@ -981,10 +1010,9 @@ error: EXPORT_SYMBOL(au8522_attach); static struct dvb_frontend_ops au8522_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Auvitek AU8522 QAM/8VSB Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index 8aff5868a5e1..033cd7ad3ca2 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -479,16 +479,16 @@ static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq) return -EINVAL; } -static int bcm3510_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int bcm3510_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct bcm3510_state* st = fe->demodulator_priv; struct bcm3510_hab_cmd_ext_acquire cmd; struct bcm3510_hab_cmd_bert_control bert; int ret; memset(&cmd,0,sizeof(cmd)); - switch (p->u.vsb.modulation) { + switch (c->modulation) { case QAM_256: cmd.ACQUIRE0.MODE = 0x1; cmd.ACQUIRE1.SYM_RATE = 0x1; @@ -499,7 +499,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe, cmd.ACQUIRE1.SYM_RATE = 0x2; cmd.ACQUIRE1.IF_FREQ = 0x1; break; -/* case QAM_256: +#if 0 + case QAM_256: cmd.ACQUIRE0.MODE = 0x3; break; case QAM_128: @@ -513,7 +514,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe, break; case QAM_16: cmd.ACQUIRE0.MODE = 0x7; - break;*/ + break; +#endif case VSB_8: cmd.ACQUIRE0.MODE = 0x8; cmd.ACQUIRE1.SYM_RATE = 0x0; @@ -552,7 +554,8 @@ static int bcm3510_set_frontend(struct dvb_frontend* fe, bcm3510_bert_reset(st); - if ((ret = bcm3510_set_freq(st,p->frequency)) < 0) + ret = bcm3510_set_freq(st, c->frequency); + if (ret < 0) return ret; memset(&st->status1,0,sizeof(st->status1)); @@ -819,10 +822,9 @@ error: EXPORT_SYMBOL(bcm3510_attach); static struct dvb_frontend_ops bcm3510_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Broadcom BCM3510 VSB/QAM frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 803000000, /* stepsize is just a guess */ diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h index 5e431ebd089b..53e4d0dbb745 100644 --- a/drivers/media/dvb/frontends/bsbe1.h +++ b/drivers/media/dvb/frontends/bsbe1.h @@ -69,18 +69,19 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_bsbe1_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; struct i2c_adapter *i2c = fe->tuner_priv; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = params->frequency / 1000; + div = p->frequency / 1000; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x80 | ((div & 0x18000) >> 10) | 0x1; diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h index c480c839b302..c2a578e1314d 100644 --- a/drivers/media/dvb/frontends/bsru6.h +++ b/drivers/media/dvb/frontends/bsru6.h @@ -101,23 +101,24 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; struct i2c_adapter *i2c = fe->tuner_priv; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (125 - 1)) / 125; // round correctly + div = (p->frequency + (125 - 1)) / 125; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; buf[3] = 0xC4; - if (params->frequency > 1530000) + if (p->frequency > 1530000) buf[3] = 0xc0; if (fe->ops.i2c_gate_ctrl) diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 0142214b0133..f2a90f990ce3 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -121,7 +121,8 @@ static int cx22700_set_inversion (struct cx22700_state* state, int inversion) } } -static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p) +static int cx22700_set_tps(struct cx22700_state *state, + struct dtv_frontend_properties *p) { static const u8 qam_tab [4] = { 0, 1, 0, 2 }; static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 }; @@ -146,25 +147,25 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet p->transmission_mode != TRANSMISSION_MODE_8K) return -EINVAL; - if (p->constellation != QPSK && - p->constellation != QAM_16 && - p->constellation != QAM_64) + if (p->modulation != QPSK && + p->modulation != QAM_16 && + p->modulation != QAM_64) return -EINVAL; - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) + if (p->hierarchy < HIERARCHY_NONE || + p->hierarchy > HIERARCHY_4) return -EINVAL; - if (p->bandwidth < BANDWIDTH_8_MHZ || p->bandwidth > BANDWIDTH_6_MHZ) + if (p->bandwidth_hz > 8000000 || p->bandwidth_hz < 6000000) return -EINVAL; - if (p->bandwidth == BANDWIDTH_7_MHZ) + if (p->bandwidth_hz == 7000000) cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10)); else cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10)); - val = qam_tab[p->constellation - QPSK]; - val |= p->hierarchy_information - HIERARCHY_NONE; + val = qam_tab[p->modulation - QPSK]; + val |= p->hierarchy - HIERARCHY_NONE; cx22700_writereg (state, 0x04, val); @@ -184,7 +185,8 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet return 0; } -static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p) +static int cx22700_get_tps(struct cx22700_state *state, + struct dtv_frontend_properties *p) { static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, @@ -199,14 +201,14 @@ static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_paramet val = cx22700_readreg (state, 0x01); if ((val & 0x7) > 4) - p->hierarchy_information = HIERARCHY_AUTO; + p->hierarchy = HIERARCHY_AUTO; else - p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); + p->hierarchy = HIERARCHY_NONE + (val & 0x7); if (((val >> 3) & 0x3) > 2) - p->constellation = QAM_AUTO; + p->modulation = QAM_AUTO; else - p->constellation = qam_tab[(val >> 3) & 0x3]; + p->modulation = qam_tab[(val >> 3) & 0x3]; val = cx22700_readreg (state, 0x02); @@ -318,33 +320,35 @@ static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22700_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx22700_state* state = fe->demodulator_priv; cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ cx22700_writereg (state, 0x00, 0x00); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - cx22700_set_inversion (state, p->inversion); - cx22700_set_tps (state, &p->u.ofdm); + cx22700_set_inversion(state, c->inversion); + cx22700_set_tps(state, c); cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ cx22700_writereg (state, 0x00, 0x01); /* restart acquire */ return 0; } -static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx22700_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx22700_state* state = fe->demodulator_priv; u8 reg09 = cx22700_readreg (state, 0x09); - p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22700_get_tps (state, &p->u.ofdm); + c->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22700_get_tps(state, c); } static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) @@ -401,10 +405,9 @@ error: } static struct dvb_frontend_ops cx22700_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Conexant CX22700 DVB-T", - .type = FE_OFDM, .frequency_min = 470000000, .frequency_max = 860000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 3139558148ba..faba82485086 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -146,7 +146,7 @@ static int cx22702_set_inversion(struct cx22702_state *state, int inversion) /* Retrieve the demod settings */ static int cx22702_get_tps(struct cx22702_state *state, - struct dvb_ofdm_parameters *p) + struct dtv_frontend_properties *p) { u8 val; @@ -157,27 +157,27 @@ static int cx22702_get_tps(struct cx22702_state *state, val = cx22702_readreg(state, 0x01); switch ((val & 0x18) >> 3) { case 0: - p->constellation = QPSK; + p->modulation = QPSK; break; case 1: - p->constellation = QAM_16; + p->modulation = QAM_16; break; case 2: - p->constellation = QAM_64; + p->modulation = QAM_64; break; } switch (val & 0x07) { case 0: - p->hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - p->hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - p->hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - p->hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; } @@ -260,14 +260,14 @@ static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int cx22702_set_tps(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx22702_set_tps(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u8 val; struct cx22702_state *state = fe->demodulator_priv; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -277,14 +277,14 @@ static int cx22702_set_tps(struct dvb_frontend *fe, /* set bandwidth */ val = cx22702_readreg(state, 0x0C) & 0xcf; - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: val |= 0x20; break; - case BANDWIDTH_7_MHZ: + case 7000000: val |= 0x10; break; - case BANDWIDTH_8_MHZ: + case 8000000: break; default: dprintk("%s: invalid bandwidth\n", __func__); @@ -292,15 +292,15 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } cx22702_writereg(state, 0x0C, val); - p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ + p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ /* use auto configuration? */ - if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) || - (p->u.ofdm.constellation == QAM_AUTO) || - (p->u.ofdm.code_rate_HP == FEC_AUTO) || - (p->u.ofdm.code_rate_LP == FEC_AUTO) || - (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) || - (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) { + if ((p->hierarchy == HIERARCHY_AUTO) || + (p->modulation == QAM_AUTO) || + (p->code_rate_HP == FEC_AUTO) || + (p->code_rate_LP == FEC_AUTO) || + (p->guard_interval == GUARD_INTERVAL_AUTO) || + (p->transmission_mode == TRANSMISSION_MODE_AUTO)) { /* TPS Source - use hardware driven values */ cx22702_writereg(state, 0x06, 0x10); @@ -316,7 +316,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } /* manually programmed values */ - switch (p->u.ofdm.constellation) { /* mask 0x18 */ + switch (p->modulation) { /* mask 0x18 */ case QPSK: val = 0x00; break; @@ -327,10 +327,10 @@ static int cx22702_set_tps(struct dvb_frontend *fe, val = 0x10; break; default: - dprintk("%s: invalid constellation\n", __func__); + dprintk("%s: invalid modulation\n", __func__); return -EINVAL; } - switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */ + switch (p->hierarchy) { /* mask 0x07 */ case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -348,7 +348,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } cx22702_writereg(state, 0x06, val); - switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */ + switch (p->code_rate_HP) { /* mask 0x38 */ case FEC_NONE: case FEC_1_2: val = 0x00; @@ -369,7 +369,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, dprintk("%s: invalid code_rate_HP\n", __func__); return -EINVAL; } - switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */ + switch (p->code_rate_LP) { /* mask 0x07 */ case FEC_NONE: case FEC_1_2: break; @@ -391,7 +391,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, } cx22702_writereg(state, 0x07, val); - switch (p->u.ofdm.guard_interval) { /* mask 0x0c */ + switch (p->guard_interval) { /* mask 0x0c */ case GUARD_INTERVAL_1_32: val = 0x00; break; @@ -408,7 +408,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, dprintk("%s: invalid guard_interval\n", __func__); return -EINVAL; } - switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */ + switch (p->transmission_mode) { /* mask 0x03 */ case TRANSMISSION_MODE_2K: break; case TRANSMISSION_MODE_8K: @@ -546,15 +546,15 @@ static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int cx22702_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx22702_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx22702_state *state = fe->demodulator_priv; u8 reg0C = cx22702_readreg(state, 0x0C); - p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22702_get_tps(state, &p->u.ofdm); + c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22702_get_tps(state, c); } static int cx22702_get_tune_settings(struct dvb_frontend *fe, @@ -603,10 +603,9 @@ error: EXPORT_SYMBOL(cx22702_attach); static const struct dvb_frontend_ops cx22702_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Conexant CX22702 DVB-T", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index bf9c999aa470..5101f10f2d7a 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -531,26 +531,27 @@ static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24110_set_frontend(struct dvb_frontend *fe) { struct cx24110_state *state = fe->demodulator_priv; - + struct dtv_frontend_properties *p = &fe->dtv_property_cache; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - cx24110_set_inversion (state, p->inversion); - cx24110_set_fec (state, p->u.qpsk.fec_inner); - cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); + cx24110_set_inversion(state, p->inversion); + cx24110_set_fec(state, p->fec_inner); + cx24110_set_symbolrate(state, p->symbol_rate); cx24110_writereg(state,0x04,0x05); /* start acquisition */ return 0; } -static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int cx24110_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24110_state *state = fe->demodulator_priv; s32 afc; unsigned sclk; @@ -571,7 +572,7 @@ static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par p->frequency += afc; p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = cx24110_get_fec (state); + p->fec_inner = cx24110_get_fec(state); return 0; } @@ -623,10 +624,9 @@ error: } static struct dvb_frontend_ops cx24110_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Conexant CX24110 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c index c341d57d5e81..3883c3b31aef 100644 --- a/drivers/media/dvb/frontends/cx24113.c +++ b/drivers/media/dvb/frontends/cx24113.c @@ -476,21 +476,21 @@ static int cx24113_init(struct dvb_frontend *fe) return ret; } -static int cx24113_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24113_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24113_state *state = fe->tuner_priv; /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */ u32 roll_off = 675; u32 bw; - bw = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000; + bw = ((c->symbol_rate/100) * roll_off) / 1000; bw += (10000000/100) + 5; bw /= 10; bw += 1000; cx24113_set_bandwidth(state, bw); - cx24113_set_frequency(state, p->frequency); + cx24113_set_frequency(state, c->frequency); msleep(5); return cx24113_get_status(fe, &bw); } @@ -547,11 +547,9 @@ static const struct dvb_tuner_ops cx24113_tuner_ops = { .release = cx24113_release, .init = cx24113_init, - .sleep = NULL, .set_params = cx24113_set_params, .get_frequency = cx24113_get_frequency, - .get_bandwidth = NULL, .get_status = cx24113_get_status, }; diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c index ccd05255d527..b48879186537 100644 --- a/drivers/media/dvb/frontends/cx24116.c +++ b/drivers/media/dvb/frontends/cx24116.c @@ -1212,25 +1212,10 @@ static int cx24116_sleep(struct dvb_frontend *fe) return 0; } -static int cx24116_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int cx24116_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - /* dvb-core told us to tune, the tv property cache will be complete, * it's safe for is to pull values and use them for tuning purposes. */ -static int cx24116_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24116_set_frontend(struct dvb_frontend *fe) { struct cx24116_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1455,12 +1440,20 @@ tuned: /* Set/Reset B/W */ return cx24116_cmd_execute(fe, &cmd); } -static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, +static int cx24116_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { + /* + * It is safe to discard "params" here, as the DVB core will sync + * fe->dtv_property_cache with fepriv->parameters_in, where the + * DVBv3 params are stored. The only practical usage for it indicate + * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is + * true. + */ + *delay = HZ / 5; - if (params) { - int ret = cx24116_set_frontend(fe, params); + if (re_tune) { + int ret = cx24116_set_frontend(fe); if (ret) return ret; } @@ -1473,10 +1466,9 @@ static int cx24116_get_algo(struct dvb_frontend *fe) } static struct dvb_frontend_ops cx24116_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Conexant CX24116/CX24118", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ @@ -1507,8 +1499,6 @@ static struct dvb_frontend_ops cx24116_ops = { .get_frontend_algo = cx24116_get_algo, .tune = cx24116_tune, - .set_property = cx24116_set_property, - .get_property = cx24116_get_property, .set_frontend = cx24116_set_frontend, }; diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index b1dd8acc607a..7e28b4ee7d4f 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -526,9 +526,9 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) * to be configured and the correct band selected. * Calculate those values. */ -static int cx24123_pll_calculate(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_pll_calculate(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24123_state *state = fe->demodulator_priv; u32 ndiv = 0, adiv = 0, vco_div = 0; int i = 0; @@ -548,8 +548,8 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe, * FILTUNE programming bits */ for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++) { agcv = &cx24123_AGC_vals[i]; - if ((agcv->symbolrate_low <= p->u.qpsk.symbol_rate) && - (agcv->symbolrate_high >= p->u.qpsk.symbol_rate)) { + if ((agcv->symbolrate_low <= p->symbol_rate) && + (agcv->symbolrate_high >= p->symbol_rate)) { state->VCAarg = agcv->VCAprogdata; state->VGAarg = agcv->VGAprogdata; state->FILTune = agcv->FILTune; @@ -601,8 +601,7 @@ static int cx24123_pll_calculate(struct dvb_frontend *fe, * Tuner cx24109 is written through a dedicated 3wire interface * on the demod chip. */ -static int cx24123_pll_writereg(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p, u32 data) +static int cx24123_pll_writereg(struct dvb_frontend *fe, u32 data) { struct cx24123_state *state = fe->demodulator_priv; unsigned long timeout; @@ -659,26 +658,26 @@ static int cx24123_pll_writereg(struct dvb_frontend *fe, return 0; } -static int cx24123_pll_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_pll_tune(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24123_state *state = fe->demodulator_priv; u8 val; dprintk("frequency=%i\n", p->frequency); - if (cx24123_pll_calculate(fe, p) != 0) { + if (cx24123_pll_calculate(fe) != 0) { err("%s: cx24123_pll_calcutate failed\n", __func__); return -EINVAL; } /* Write the new VCO/VGA */ - cx24123_pll_writereg(fe, p, state->VCAarg); - cx24123_pll_writereg(fe, p, state->VGAarg); + cx24123_pll_writereg(fe, state->VCAarg); + cx24123_pll_writereg(fe, state->VGAarg); /* Write the new bandselect and pll args */ - cx24123_pll_writereg(fe, p, state->bandselectarg); - cx24123_pll_writereg(fe, p, state->pllarg); + cx24123_pll_writereg(fe, state->bandselectarg); + cx24123_pll_writereg(fe, state->pllarg); /* set the FILTUNE voltage */ val = cx24123_readreg(state, 0x28) & ~0x3; @@ -925,10 +924,10 @@ static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; } -static int cx24123_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_set_frontend(struct dvb_frontend *fe) { struct cx24123_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; dprintk("\n"); @@ -936,16 +935,16 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, state->config->set_ts_params(fe, 0); state->currentfreq = p->frequency; - state->currentsymbolrate = p->u.qpsk.symbol_rate; + state->currentsymbolrate = p->symbol_rate; cx24123_set_inversion(state, p->inversion); - cx24123_set_fec(state, p->u.qpsk.fec_inner); - cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate); + cx24123_set_fec(state, p->fec_inner); + cx24123_set_symbolrate(state, p->symbol_rate); if (!state->config->dont_use_pll) - cx24123_pll_tune(fe, p); + cx24123_pll_tune(fe); else if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); else err("it seems I don't have a tuner..."); @@ -960,9 +959,9 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, return 0; } -static int cx24123_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cx24123_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx24123_state *state = fe->demodulator_priv; dprintk("\n"); @@ -971,12 +970,12 @@ static int cx24123_get_frontend(struct dvb_frontend *fe, err("%s: Failed to get inversion status\n", __func__); return -EREMOTEIO; } - if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) { + if (cx24123_get_fec(state, &p->fec_inner) != 0) { err("%s: Failed to get fec status\n", __func__); return -EREMOTEIO; } p->frequency = state->currentfreq; - p->u.qpsk.symbol_rate = state->currentsymbolrate; + p->symbol_rate = state->currentsymbolrate; return 0; } @@ -1007,15 +1006,15 @@ static int cx24123_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) } static int cx24123_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { int retval = 0; - if (params != NULL) - retval = cx24123_set_frontend(fe, params); + if (re_tune) + retval = cx24123_set_frontend(fe); if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) cx24123_read_status(fe, status); @@ -1126,10 +1125,9 @@ error: EXPORT_SYMBOL(cx24123_attach); static struct dvb_frontend_ops cx24123_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Conexant CX24123/CX24109", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h index 03cab7b547fb..cf0f546aa1d1 100644 --- a/drivers/media/dvb/frontends/cxd2820r.h +++ b/drivers/media/dvb/frontends/cxd2820r.h @@ -63,19 +63,6 @@ struct cxd2820r_config { */ bool spec_inv; - /* IFs for all used modes. - * Default: none, must set - * Values: <kHz> - */ - u16 if_dvbt_6; - u16 if_dvbt_7; - u16 if_dvbt_8; - u16 if_dvbt2_5; - u16 if_dvbt2_6; - u16 if_dvbt2_7; - u16 if_dvbt2_8; - u16 if_dvbc; - /* GPIOs for all used modes. * Default: none, disabled * Values: <see above> diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c index b85f5011e344..945404991529 100644 --- a/drivers/media/dvb/frontends/cxd2820r_c.c +++ b/drivers/media/dvb/frontends/cxd2820r_c.c @@ -21,13 +21,13 @@ #include "cxd2820r_priv.h" -int cxd2820r_set_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +int cxd2820r_set_frontend_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u8 buf[2]; + u32 if_freq; u16 if_ctl; u64 num; struct reg_val_mask tab[] = { @@ -56,9 +56,9 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe, /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); + fe->ops.tuner_ops.set_params(fe); - if (priv->delivery_system != SYS_DVBC_ANNEX_AC) { + if (priv->delivery_system != SYS_DVBC_ANNEX_A) { for (i = 0; i < ARRAY_SIZE(tab); i++) { ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val, tab[i].mask); @@ -67,10 +67,20 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe, } } - priv->delivery_system = SYS_DVBC_ANNEX_AC; + priv->delivery_system = SYS_DVBC_ANNEX_A; priv->ber_running = 0; /* tune stops BER counter */ - num = priv->cfg.if_dvbc; + /* program IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto error; + } else + if_freq = 0; + + dbg("%s: if_freq=%d", __func__, if_freq); + + num = if_freq / 1000; /* Hz => kHz */ num *= 0x4000; if_ctl = cxd2820r_div_u64_round_closest(num, 41000); buf[0] = (if_ctl >> 8) & 0x3f; @@ -94,8 +104,7 @@ error: return ret; } -int cxd2820r_get_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_get_frontend_c(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c index 036480f967b7..93e1b12e7907 100644 --- a/drivers/media/dvb/frontends/cxd2820r_core.c +++ b/drivers/media/dvb/frontends/cxd2820r_core.c @@ -240,422 +240,234 @@ error: return ret; } -/* lock FE */ -static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe) -{ - int ret = 0; - dbg("%s: active_fe=%d", __func__, active_fe); - - mutex_lock(&priv->fe_lock); - - /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - if (priv->active_fe == active_fe) - ; - else if (priv->active_fe == -1) - priv->active_fe = active_fe; - else - ret = -EBUSY; - - mutex_unlock(&priv->fe_lock); - - return ret; -} - -/* unlock FE */ -static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe) -{ - dbg("%s: active_fe=%d", __func__, active_fe); - - mutex_lock(&priv->fe_lock); - - /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - if (priv->active_fe == active_fe) - priv->active_fe = -1; - - mutex_unlock(&priv->fe_lock); - - return; -} - /* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */ u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor) { return div_u64(dividend + (divisor / 2), divisor); } -static int cxd2820r_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cxd2820r_set_frontend(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (priv->delivery_system) { - case SYS_UNDEFINED: - if (c->delivery_system == SYS_DVBT) { - /* SLEEP => DVB-T */ - ret = cxd2820r_set_frontend_t(fe, p); - } else { - /* SLEEP => DVB-T2 */ - ret = cxd2820r_set_frontend_t2(fe, p); - } - break; - case SYS_DVBT: - if (c->delivery_system == SYS_DVBT) { - /* DVB-T => DVB-T */ - ret = cxd2820r_set_frontend_t(fe, p); - } else if (c->delivery_system == SYS_DVBT2) { - /* DVB-T => DVB-T2 */ - ret = cxd2820r_sleep_t(fe); - if (ret) - break; - ret = cxd2820r_set_frontend_t2(fe, p); - } - break; - case SYS_DVBT2: - if (c->delivery_system == SYS_DVBT2) { - /* DVB-T2 => DVB-T2 */ - ret = cxd2820r_set_frontend_t2(fe, p); - } else if (c->delivery_system == SYS_DVBT) { - /* DVB-T2 => DVB-T */ - ret = cxd2820r_sleep_t2(fe); - if (ret) - break; - ret = cxd2820r_set_frontend_t(fe, p); - } - break; - default: - dbg("%s: error state=%d", __func__, - priv->delivery_system); - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; - - ret = cxd2820r_set_frontend_c(fe, p); + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (c->delivery_system) { + case SYS_DVBT: + ret = cxd2820r_init_t(fe); + if (ret < 0) + goto err; + ret = cxd2820r_set_frontend_t(fe); + if (ret < 0) + goto err; + break; + case SYS_DVBT2: + ret = cxd2820r_init_t(fe); + if (ret < 0) + goto err; + ret = cxd2820r_set_frontend_t2(fe); + if (ret < 0) + goto err; + break; + case SYS_DVBC_ANNEX_A: + ret = cxd2820r_init_c(fe); + if (ret < 0) + goto err; + ret = cxd2820r_set_frontend_c(fe); + if (ret < 0) + goto err; + break; + default: + dbg("%s: error state=%d", __func__, fe->dtv_property_cache.delivery_system); + ret = -EINVAL; + break; } - +err: return ret; } - static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_status_t(fe, status); - break; - case SYS_DVBT2: - ret = cxd2820r_read_status_t2(fe, status); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_status_t(fe, status); + break; + case SYS_DVBT2: + ret = cxd2820r_read_status_t2(fe, status); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_status_c(fe, status); + break; + default: + ret = -EINVAL; + break; } - return ret; } -static int cxd2820r_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int cxd2820r_get_frontend(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_get_frontend_t(fe, p); - break; - case SYS_DVBT2: - ret = cxd2820r_get_frontend_t2(fe, p); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; - - ret = cxd2820r_get_frontend_c(fe, p); + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_get_frontend_t(fe); + break; + case SYS_DVBT2: + ret = cxd2820r_get_frontend_t2(fe); + break; + case SYS_DVBC_ANNEX_A: + ret = cxd2820r_get_frontend_c(fe); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_ber_t(fe, ber); - break; - case SYS_DVBT2: - ret = cxd2820r_read_ber_t2(fe, ber); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_ber_t(fe, ber); + break; + case SYS_DVBT2: + ret = cxd2820r_read_ber_t2(fe, ber); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_ber_c(fe, ber); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_signal_strength_t(fe, strength); - break; - case SYS_DVBT2: - ret = cxd2820r_read_signal_strength_t2(fe, strength); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_signal_strength_t(fe, strength); + break; + case SYS_DVBT2: + ret = cxd2820r_read_signal_strength_t2(fe, strength); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_signal_strength_c(fe, strength); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_snr_t(fe, snr); - break; - case SYS_DVBT2: - ret = cxd2820r_read_snr_t2(fe, snr); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_snr_t(fe, snr); + break; + case SYS_DVBT2: + ret = cxd2820r_read_snr_t2(fe, snr); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_snr_c(fe, snr); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_read_ucblocks_t(fe, ucblocks); - break; - case SYS_DVBT2: - ret = cxd2820r_read_ucblocks_t2(fe, ucblocks); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_read_ucblocks_t(fe, ucblocks); + break; + case SYS_DVBT2: + ret = cxd2820r_read_ucblocks_t2(fe, ucblocks); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_read_ucblocks_c(fe, ucblocks); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_init(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; - int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - priv->delivery_system = SYS_UNDEFINED; - /* delivery system is unknown at that (init) phase */ - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - ret = cxd2820r_init_t(fe); - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; - - ret = cxd2820r_init_c(fe); - } - - return ret; + return 0; } static int cxd2820r_sleep(struct dvb_frontend *fe) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_sleep_t(fe); - break; - case SYS_DVBT2: - ret = cxd2820r_sleep_t2(fe); - break; - default: - ret = -EINVAL; - } - - cxd2820r_unlock(priv, 0); - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_sleep_t(fe); + break; + case SYS_DVBT2: + ret = cxd2820r_sleep_t2(fe); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_sleep_c(fe); - - cxd2820r_unlock(priv, 1); + break; + default: + ret = -EINVAL; + break; } - return ret; } static int cxd2820r_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *s) + struct dvb_frontend_tune_settings *s) { - struct cxd2820r_priv *priv = fe->demodulator_priv; int ret; - dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); - - if (fe->ops.info.type == FE_OFDM) { - /* DVB-T/T2 */ - ret = cxd2820r_lock(priv, 0); - if (ret) - return ret; - - switch (fe->dtv_property_cache.delivery_system) { - case SYS_DVBT: - ret = cxd2820r_get_tune_settings_t(fe, s); - break; - case SYS_DVBT2: - ret = cxd2820r_get_tune_settings_t2(fe, s); - break; - default: - ret = -EINVAL; - } - } else { - /* DVB-C */ - ret = cxd2820r_lock(priv, 1); - if (ret) - return ret; + dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); + switch (fe->dtv_property_cache.delivery_system) { + case SYS_DVBT: + ret = cxd2820r_get_tune_settings_t(fe, s); + break; + case SYS_DVBT2: + ret = cxd2820r_get_tune_settings_t2(fe, s); + break; + case SYS_DVBC_ANNEX_A: ret = cxd2820r_get_tune_settings_c(fe, s); + break; + default: + ret = -EINVAL; + break; } - return ret; } -static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -664,7 +476,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system); /* switch between DVB-T and DVB-T2 when tune fails */ - if (priv->last_tune_failed) { + if (priv->last_tune_failed && (priv->delivery_system != SYS_DVBC_ANNEX_A)) { if (priv->delivery_system == SYS_DVBT) c->delivery_system = SYS_DVBT2; else @@ -672,7 +484,7 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe, } /* set frontend */ - ret = cxd2820r_set_frontend(fe, p); + ret = cxd2820r_set_frontend(fe); if (ret) goto error; @@ -727,9 +539,7 @@ static void cxd2820r_release(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; dbg("%s", __func__); - if (fe->ops.info.type == FE_OFDM) - kfree(priv); - + kfree(priv); return; } @@ -742,128 +552,79 @@ static int cxd2820r_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return cxd2820r_wr_reg_mask(priv, 0xdb, enable ? 1 : 0, 0x1); } -static const struct dvb_frontend_ops cxd2820r_ops[2]; +static const struct dvb_frontend_ops cxd2820r_ops = { + .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, + /* default: DVB-T/T2 */ + .info = { + .name = "Sony CXD2820R (DVB-T/T2)", + + .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_64 | + 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 + }, -struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, - struct i2c_adapter *i2c, struct dvb_frontend *fe) -{ - int ret; - struct cxd2820r_priv *priv = NULL; - u8 tmp; + .release = cxd2820r_release, + .init = cxd2820r_init, + .sleep = cxd2820r_sleep, - if (fe == NULL) { - /* FE0 */ - /* allocate memory for the internal priv */ - priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); - if (priv == NULL) - goto error; + .get_tune_settings = cxd2820r_get_tune_settings, + .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, - /* setup the priv */ - priv->i2c = i2c; - memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config)); - mutex_init(&priv->fe_lock); + .get_frontend = cxd2820r_get_frontend, - priv->active_fe = -1; /* NONE */ + .get_frontend_algo = cxd2820r_get_frontend_algo, + .search = cxd2820r_search, - /* check if the demod is there */ - priv->bank[0] = priv->bank[1] = 0xff; - ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); - dbg("%s: chip id=%02x", __func__, tmp); - if (ret || tmp != 0xe1) - goto error; + .read_status = cxd2820r_read_status, + .read_snr = cxd2820r_read_snr, + .read_ber = cxd2820r_read_ber, + .read_ucblocks = cxd2820r_read_ucblocks, + .read_signal_strength = cxd2820r_read_signal_strength, +}; - /* create frontends */ - memcpy(&priv->fe[0].ops, &cxd2820r_ops[0], - sizeof(struct dvb_frontend_ops)); - memcpy(&priv->fe[1].ops, &cxd2820r_ops[1], - sizeof(struct dvb_frontend_ops)); +struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, + struct i2c_adapter *i2c, + struct dvb_frontend *fe) +{ + struct cxd2820r_priv *priv = NULL; + int ret; + u8 tmp; - priv->fe[0].demodulator_priv = priv; - priv->fe[1].demodulator_priv = priv; + priv = kzalloc(sizeof (struct cxd2820r_priv), GFP_KERNEL); + if (!priv) + goto error; - return &priv->fe[0]; + priv->i2c = i2c; + memcpy(&priv->cfg, cfg, sizeof (struct cxd2820r_config)); - } else { - /* FE1: FE0 given as pointer, just return FE1 we have - * already created */ - priv = fe->demodulator_priv; - return &priv->fe[1]; - } + priv->bank[0] = priv->bank[1] = 0xff; + ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp); + dbg("%s: chip id=%02x", __func__, tmp); + if (ret || tmp != 0xe1) + goto error; + memcpy(&priv->fe.ops, &cxd2820r_ops, sizeof (struct dvb_frontend_ops)); + priv->fe.demodulator_priv = priv; + return &priv->fe; error: kfree(priv); return NULL; } EXPORT_SYMBOL(cxd2820r_attach); -static const struct dvb_frontend_ops cxd2820r_ops[2] = { - { - /* DVB-T/T2 */ - .info = { - .name = "Sony CXD2820R (DVB-T/T2)", - .type = FE_OFDM, - .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_64 | 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 - }, - - .release = cxd2820r_release, - .init = cxd2820r_init, - .sleep = cxd2820r_sleep, - - .get_tune_settings = cxd2820r_get_tune_settings, - .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, - - .get_frontend = cxd2820r_get_frontend, - - .get_frontend_algo = cxd2820r_get_frontend_algo, - .search = cxd2820r_search, - - .read_status = cxd2820r_read_status, - .read_snr = cxd2820r_read_snr, - .read_ber = cxd2820r_read_ber, - .read_ucblocks = cxd2820r_read_ucblocks, - .read_signal_strength = cxd2820r_read_signal_strength, - }, - { - /* DVB-C */ - .info = { - .name = "Sony CXD2820R (DVB-C)", - .type = FE_QAM, - .caps = - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO - }, - - .release = cxd2820r_release, - .init = cxd2820r_init, - .sleep = cxd2820r_sleep, - - .get_tune_settings = cxd2820r_get_tune_settings, - .i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl, - - .set_frontend = cxd2820r_set_frontend, - .get_frontend = cxd2820r_get_frontend, - - .read_status = cxd2820r_read_status, - .read_snr = cxd2820r_read_snr, - .read_ber = cxd2820r_read_ber, - .read_ucblocks = cxd2820r_read_ucblocks, - .read_signal_strength = cxd2820r_read_signal_strength, - }, -}; - - MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Sony CXD2820R demodulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h index 95539134efdb..9a9822cad9cd 100644 --- a/drivers/media/dvb/frontends/cxd2820r_priv.h +++ b/drivers/media/dvb/frontends/cxd2820r_priv.h @@ -48,12 +48,9 @@ struct reg_val_mask { struct cxd2820r_priv { struct i2c_adapter *i2c; - struct dvb_frontend fe[2]; + struct dvb_frontend fe; struct cxd2820r_config cfg; - struct mutex fe_lock; /* FE lock */ - int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */ - bool ber_running; u8 bank[2]; @@ -89,11 +86,9 @@ int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val); /* cxd2820r_c.c */ -int cxd2820r_get_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p); +int cxd2820r_get_frontend_c(struct dvb_frontend *fe); -int cxd2820r_set_frontend_c(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params); +int cxd2820r_set_frontend_c(struct dvb_frontend *fe); int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status); @@ -114,11 +109,9 @@ int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe, /* cxd2820r_t.c */ -int cxd2820r_get_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p); +int cxd2820r_get_frontend_t(struct dvb_frontend *fe); -int cxd2820r_set_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params); +int cxd2820r_set_frontend_t(struct dvb_frontend *fe); int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status); @@ -139,11 +132,9 @@ int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe, /* cxd2820r_t2.c */ -int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p); +int cxd2820r_get_frontend_t2(struct dvb_frontend *fe); -int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params); +int cxd2820r_set_frontend_t2(struct dvb_frontend *fe); int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status); diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c index a04f9c810101..1a026239cdcc 100644 --- a/drivers/media/dvb/frontends/cxd2820r_t.c +++ b/drivers/media/dvb/frontends/cxd2820r_t.c @@ -21,13 +21,12 @@ #include "cxd2820r_priv.h" -int cxd2820r_set_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_set_frontend_t(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u32 if_khz, if_ctl; + int ret, i, bw_i; + u32 if_freq, if_ctl; u64 num; u8 buf[3], bw_param; u8 bw_params1[][5] = { @@ -57,6 +56,23 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz); + switch (c->bandwidth_hz) { + case 6000000: + bw_i = 0; + bw_param = 2; + break; + case 7000000: + bw_i = 1; + bw_param = 1; + break; + case 8000000: + bw_i = 2; + bw_param = 0; + break; + default: + return -EINVAL; + } + /* update GPIOs */ ret = cxd2820r_gpio(fe); if (ret) @@ -64,7 +80,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (priv->delivery_system != SYS_DVBT) { for (i = 0; i < ARRAY_SIZE(tab); i++) { @@ -78,27 +94,17 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, priv->delivery_system = SYS_DVBT; priv->ber_running = 0; /* tune stops BER counter */ - switch (c->bandwidth_hz) { - case 6000000: - if_khz = priv->cfg.if_dvbt_6; - i = 0; - bw_param = 2; - break; - case 7000000: - if_khz = priv->cfg.if_dvbt_7; - i = 1; - bw_param = 1; - break; - case 8000000: - if_khz = priv->cfg.if_dvbt_8; - i = 2; - bw_param = 0; - break; - default: - return -EINVAL; - } + /* program IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto error; + } else + if_freq = 0; + + dbg("%s: if_freq=%d", __func__, if_freq); - num = if_khz; + num = if_freq / 1000; /* Hz => kHz */ num *= 0x1000000; if_ctl = cxd2820r_div_u64_round_closest(num, 41000); buf[0] = ((if_ctl >> 16) & 0xff); @@ -109,7 +115,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, if (ret) goto error; - ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5); + ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[bw_i], 5); if (ret) goto error; @@ -117,7 +123,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe, if (ret) goto error; - ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2); + ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[bw_i], 2); if (ret) goto error; @@ -135,8 +141,7 @@ error: return ret; } -int cxd2820r_get_frontend_t(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_get_frontend_t(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c index 6548588309f7..3a5759e0d235 100644 --- a/drivers/media/dvb/frontends/cxd2820r_t2.c +++ b/drivers/media/dvb/frontends/cxd2820r_t2.c @@ -21,13 +21,12 @@ #include "cxd2820r_priv.h" -int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; - u32 if_khz, if_ctl; + int ret, i, bw_i; + u32 if_freq, if_ctl; u64 num; u8 buf[3], bw_param; u8 bw_params1[][5] = { @@ -71,6 +70,27 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz); + switch (c->bandwidth_hz) { + case 5000000: + bw_i = 0; + bw_param = 3; + break; + case 6000000: + bw_i = 1; + bw_param = 2; + break; + case 7000000: + bw_i = 2; + bw_param = 1; + break; + case 8000000: + bw_i = 3; + bw_param = 0; + break; + default: + return -EINVAL; + } + /* update GPIOs */ ret = cxd2820r_gpio(fe); if (ret) @@ -78,7 +98,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); + fe->ops.tuner_ops.set_params(fe); if (priv->delivery_system != SYS_DVBT2) { for (i = 0; i < ARRAY_SIZE(tab); i++) { @@ -91,32 +111,17 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, priv->delivery_system = SYS_DVBT2; - switch (c->bandwidth_hz) { - case 5000000: - if_khz = priv->cfg.if_dvbt2_5; - i = 0; - bw_param = 3; - break; - case 6000000: - if_khz = priv->cfg.if_dvbt2_6; - i = 1; - bw_param = 2; - break; - case 7000000: - if_khz = priv->cfg.if_dvbt2_7; - i = 2; - bw_param = 1; - break; - case 8000000: - if_khz = priv->cfg.if_dvbt2_8; - i = 3; - bw_param = 0; - break; - default: - return -EINVAL; - } + /* program IF frequency */ + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto error; + } else + if_freq = 0; + + dbg("%s: if_freq=%d", __func__, if_freq); - num = if_khz; + num = if_freq / 1000; /* Hz => kHz */ num *= 0x1000000; if_ctl = cxd2820r_div_u64_round_closest(num, 41000); buf[0] = ((if_ctl >> 16) & 0xff); @@ -127,7 +132,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe, if (ret) goto error; - ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5); + ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[bw_i], 5); if (ret) goto error; @@ -150,8 +155,7 @@ error: } -int cxd2820r_get_frontend_t2(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +int cxd2820r_get_frontend_t2(struct dvb_frontend *fe) { struct cxd2820r_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index dc1cb17a6ea7..3b024bfe980a 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -150,7 +150,7 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) } \ } while (0) -static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +static int dib0070_set_bandwidth(struct dvb_frontend *fe) { struct dib0070_state *state = fe->tuner_priv; u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; @@ -335,7 +335,7 @@ static const struct dib0070_lna_match dib0070_lna[] = { }; #define LPF 100 -static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +static int dib0070_tune_digital(struct dvb_frontend *fe) { struct dib0070_state *state = fe->tuner_priv; @@ -507,7 +507,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par *tune_state = CT_TUNER_STEP_5; } else if (*tune_state == CT_TUNER_STEP_5) { - dib0070_set_bandwidth(fe, ch); + dib0070_set_bandwidth(fe); *tune_state = CT_TUNER_STOP; } else { ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ @@ -516,7 +516,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par } -static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dib0070_tune(struct dvb_frontend *fe) { struct dib0070_state *state = fe->tuner_priv; uint32_t ret; @@ -524,7 +524,7 @@ static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters state->tune_state = CT_TUNER_START; do { - ret = dib0070_tune_digital(fe, p); + ret = dib0070_tune_digital(fe); if (ret != FE_CALLBACK_TIME_NEVER) msleep(ret/10); else diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index b174d1c78583..224d81e85091 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -717,6 +717,34 @@ static const u16 rf_ramp_pwm_cband_7090[] = { (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ }; +static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = { + 186, + 40, + 746, + (10 << 10) | 345, + (0 << 10) | 746, + (0 << 10) | 0, + (0 << 10) | 0, + (28 << 10) | 200, + (0 << 10) | 345, + (20 << 10) | 0, + (0 << 10) | 200, +}; + +static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = { + 86, + 40, + 345, + (0 << 10) | 0, + (0 << 10) | 0, + (0 << 10) | 0, + (0 << 10) | 0, + (28 << 10) | 200, + (0 << 10) | 345, + (20 << 10) | 0, + (0 << 10) | 200, +}; + static const u16 rf_ramp_pwm_cband_8090[] = { 345, /* max RF gain in 10th of dB */ 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ @@ -1076,8 +1104,16 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090); - else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + else if (state->identity.version == SOC_7090_P1G_11R1 + || state->identity.version == SOC_7090_P1G_21R1) { + if (state->config->is_dib7090e) { + if (state->rf_ramp == NULL) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity); + else + dib0090_set_rframp_pwm(state, state->rf_ramp); + } else + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + } } else { dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); @@ -1112,13 +1148,21 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) else dib0090_write_reg(state, 0x32, (0 << 11)); - dib0090_write_reg(state, 0x04, 0x01); + dib0090_write_reg(state, 0x04, 0x03); dib0090_write_reg(state, 0x39, (1 << 10)); } } EXPORT_SYMBOL(dib0090_pwm_gain_reset); +void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff) +{ + struct dib0090_state *state = fe->tuner_priv; + if (DC_servo_cutoff < 4) + dib0090_write_reg(state, 0x04, DC_servo_cutoff); +} +EXPORT_SYMBOL(dib0090_set_dc_servo); + static u32 dib0090_get_slow_adc_val(struct dib0090_state *state) { u16 adc_val = dib0090_read_reg(state, 0x1d); @@ -1305,7 +1349,7 @@ void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * EXPORT_SYMBOL(dib0090_get_current_gain); -u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) +u16 dib0090_get_wbd_target(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000; @@ -1342,9 +1386,57 @@ u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) return state->wbd_offset + wbd_tcold; } +EXPORT_SYMBOL(dib0090_get_wbd_target); +u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + return state->wbd_offset; +} EXPORT_SYMBOL(dib0090_get_wbd_offset); +int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3) +{ + struct dib0090_state *state = fe->tuner_priv; + + dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xfff8) + | ((sw3 & 1) << 2) | ((sw2 & 1) << 1) | (sw1 & 1)); + + return 0; +} +EXPORT_SYMBOL(dib0090_set_switch); + +int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff) +{ + struct dib0090_state *state = fe->tuner_priv; + + dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x7fff) + | ((onoff & 1) << 15)); + return 0; +} +EXPORT_SYMBOL(dib0090_set_vga); + +int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity) +{ + struct dib0090_state *state = fe->tuner_priv; + + if ((!state->identity.p1g) || (!state->identity.in_soc) + || ((state->identity.version != SOC_7090_P1G_21R1) + && (state->identity.version != SOC_7090_P1G_11R1))) { + dprintk("%s() function can only be used for dib7090P", __func__); + return -ENODEV; + } + + if (cfg_sensitivity) + state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity; + else + state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci; + dib0090_pwm_gain_reset(fe); + + return 0; +} +EXPORT_SYMBOL(dib0090_update_rframp_7090); + static const u16 dib0090_defaults[] = { 25, 0x01, @@ -1430,7 +1522,7 @@ static void dib0090_set_default_config(struct dib0090_state *state, const u16 * #define POLY_MIN (u8) 0 #define POLY_MAX (u8) 8 -void dib0090_set_EFUSE(struct dib0090_state *state) +static void dib0090_set_EFUSE(struct dib0090_state *state) { u8 c, h, n; u16 e2, e4; @@ -1505,7 +1597,10 @@ static int dib0090_reset(struct dvb_frontend *fe) dib0090_set_EFUSE(state); /* Congigure in function of the crystal */ - if (state->config->io.clock_khz >= 24000) + if (state->config->force_crystal_mode != 0) + dib0090_write_reg(state, 0x14, + state->config->force_crystal_mode & 3); + else if (state->config->io.clock_khz >= 24000) dib0090_write_reg(state, 0x14, 1); else dib0090_write_reg(state, 0x14, 2); @@ -1951,6 +2046,52 @@ static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = { #endif }; +static const struct dib0090_tuning dib0090_tuning_table_cband_7090e_sensitivity[] = { +#ifdef CONFIG_BAND_CBAND + { 300000, 0 , 3, 0x8105, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, + { 380000, 0 , 10, 0x810F, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, + { 600000, 0 , 10, 0x815E, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 660000, 0 , 5, 0x85E3, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 720000, 0 , 5, 0x852E, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 860000, 0 , 4, 0x85E5, 0x280, 0x2d12, 0xb84e, EN_CAB }, +#endif +}; + +int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity) +{ + struct dib0090_state *state = fe->tuner_priv; + const struct dib0090_tuning *tune = + dib0090_tuning_table_cband_7090e_sensitivity; + const struct dib0090_tuning dib0090_tuning_table_cband_7090e_aci[] = { + { 300000, 0 , 3, 0x8165, 0x2c0, 0x2d12, 0xb84e, EN_CAB }, + { 650000, 0 , 4, 0x815B, 0x280, 0x2d12, 0xb84e, EN_CAB }, + { 860000, 0 , 5, 0x84EF, 0x280, 0x2d12, 0xb84e, EN_CAB }, + }; + + if ((!state->identity.p1g) || (!state->identity.in_soc) + || ((state->identity.version != SOC_7090_P1G_21R1) + && (state->identity.version != SOC_7090_P1G_11R1))) { + dprintk("%s() function can only be used for dib7090", __func__); + return -ENODEV; + } + + if (cfg_sensitivity) + tune = dib0090_tuning_table_cband_7090e_sensitivity; + else + tune = dib0090_tuning_table_cband_7090e_aci; + + while (state->rf_request > tune->max_freq) + tune++; + + dib0090_write_reg(state, 0x09, (dib0090_read_reg(state, 0x09) & 0x8000) + | (tune->lna_bias & 0x7fff)); + dib0090_write_reg(state, 0x0b, (dib0090_read_reg(state, 0x0b) & 0xf83f) + | ((tune->lna_tune << 6) & 0x07c0)); + return 0; +} +EXPORT_SYMBOL(dib0090_update_tuning_table_7090); + static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state) { int ret = 0; @@ -2199,12 +2340,18 @@ static int dib0090_tune(struct dvb_frontend *fe) if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF || state->current_band & BAND_UHF) { state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_cband_7090; + if (state->config->is_dib7090e) + tune = dib0090_tuning_table_cband_7090e_sensitivity; + else + tune = dib0090_tuning_table_cband_7090; } } else { /* Use the CBAND input for all band under UHF */ if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) { state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_cband_7090; + if (state->config->is_dib7090e) + tune = dib0090_tuning_table_cband_7090e_sensitivity; + else + tune = dib0090_tuning_table_cband_7090; } } } else @@ -2419,7 +2566,7 @@ static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) return 0; } -static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int dib0090_set_params(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; u32 ret; diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h index 13d85244ec16..781dc49de45b 100644 --- a/drivers/media/dvb/frontends/dib0090.h +++ b/drivers/media/dvb/frontends/dib0090.h @@ -71,6 +71,8 @@ struct dib0090_config { u8 fref_clock_ratio; u16 force_cband_input; struct dib0090_wbd_slope *wbd; + u8 is_dib7090e; + u8 force_crystal_mode; }; #if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) @@ -78,13 +80,21 @@ extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); -extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); +extern u16 dib0090_get_wbd_target(struct dvb_frontend *tuner); +extern u16 dib0090_get_wbd_offset(struct dvb_frontend *fe); extern int dib0090_gain_control(struct dvb_frontend *fe); extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); +extern void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff); +extern int dib0090_set_switch(struct dvb_frontend *fe, u8 sw1, u8 sw2, u8 sw3); +extern int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff); +extern int dib0090_update_rframp_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity); +extern int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity); #else -static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; @@ -106,7 +116,13 @@ static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } -static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +static inline u16 dib0090_get_wbd_target(struct dvb_frontend *tuner) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return 0; @@ -134,6 +150,38 @@ static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } + +static inline void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline int dib0090_set_switch(struct dvb_frontend *fe, + u8 sw1, u8 sw2, u8 sw3) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib0090_set_vga(struct dvb_frontend *fe, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib0090_update_rframp_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, + u8 cfg_sensitivity) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index 437904cbf3e6..af91e0c92339 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -112,39 +112,37 @@ static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ } }; -static int dib3000mb_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep); +static int dib3000mb_get_frontend(struct dvb_frontend* fe); -static int dib3000mb_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep, int tuner) +static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner) { struct dib3000_state* state = fe->demodulator_priv; - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; fe_code_rate_t fe_cr = FEC_NONE; int search_state, seq; if (tuner && fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); deb_setf("bandwidth: "); - switch (ofdm->bandwidth) { - case BANDWIDTH_8_MHZ: + switch (c->bandwidth_hz) { + case 8000000: deb_setf("8 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); break; - case BANDWIDTH_7_MHZ: + case 7000000: deb_setf("7 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz); break; - case BANDWIDTH_6_MHZ: + case 6000000: deb_setf("6 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz); break; - case BANDWIDTH_AUTO: + case 0: return -EOPNOTSUPP; default: err("unknown bandwidth value."); @@ -154,7 +152,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); deb_setf("transmission mode: "); - switch (ofdm->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: deb_setf("2k\n"); wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); @@ -171,7 +169,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } deb_setf("guard: "); - switch (ofdm->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_1_32: deb_setf("1_32\n"); wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); @@ -196,7 +194,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } deb_setf("inversion: "); - switch (fep->inversion) { + switch (c->inversion) { case INVERSION_OFF: deb_setf("off\n"); wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); @@ -212,8 +210,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, return -EINVAL; } - deb_setf("constellation: "); - switch (ofdm->constellation) { + deb_setf("modulation: "); + switch (c->modulation) { case QPSK: deb_setf("qpsk\n"); wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); @@ -232,7 +230,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, return -EINVAL; } deb_setf("hierarchy: "); - switch (ofdm->hierarchy_information) { + switch (c->hierarchy) { case HIERARCHY_NONE: deb_setf("none "); /* fall through */ @@ -256,16 +254,16 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } deb_setf("hierarchy: "); - if (ofdm->hierarchy_information == HIERARCHY_NONE) { + if (c->hierarchy == HIERARCHY_NONE) { deb_setf("none\n"); wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); - fe_cr = ofdm->code_rate_HP; - } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { + fe_cr = c->code_rate_HP; + } else if (c->hierarchy != HIERARCHY_AUTO) { deb_setf("on\n"); wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); - fe_cr = ofdm->code_rate_LP; + fe_cr = c->code_rate_LP; } deb_setf("fec: "); switch (fe_cr) { @@ -300,9 +298,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, } seq = dib3000_seq - [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] - [ofdm->guard_interval == GUARD_INTERVAL_AUTO] - [fep->inversion == INVERSION_AUTO]; + [c->transmission_mode == TRANSMISSION_MODE_AUTO] + [c->guard_interval == GUARD_INTERVAL_AUTO] + [c->inversion == INVERSION_AUTO]; deb_setf("seq? %d\n", seq); @@ -310,8 +308,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, wr(DIB3000MB_REG_ISI, seq ? DIB3000MB_ISI_INHIBIT : DIB3000MB_ISI_ACTIVATE); - if (ofdm->transmission_mode == TRANSMISSION_MODE_2K) { - if (ofdm->guard_interval == GUARD_INTERVAL_1_8) { + if (c->transmission_mode == TRANSMISSION_MODE_2K) { + if (c->guard_interval == GUARD_INTERVAL_1_8) { wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_2K_1_8); } else { wr(DIB3000MB_REG_SYNC_IMPROVEMENT, DIB3000MB_SYNC_IMPROVE_DEFAULT); @@ -339,10 +337,10 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, wr_foreach(dib3000mb_reg_agc_bandwidth, dib3000mb_agc_bandwidth_low); /* something has to be auto searched */ - if (ofdm->constellation == QAM_AUTO || - ofdm->hierarchy_information == HIERARCHY_AUTO || + if (c->modulation == QAM_AUTO || + c->hierarchy == HIERARCHY_AUTO || fe_cr == FEC_AUTO || - fep->inversion == INVERSION_AUTO) { + c->inversion == INVERSION_AUTO) { int as_count=0; deb_setf("autosearch enabled.\n"); @@ -361,10 +359,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count); if (search_state == 1) { - struct dvb_frontend_parameters feps; - if (dib3000mb_get_frontend(fe, &feps) == 0) { + if (dib3000mb_get_frontend(fe) == 0) { deb_setf("reading tuning data from frontend succeeded.\n"); - return dib3000mb_set_frontend(fe, &feps, 0); + return dib3000mb_set_frontend(fe, 0); } } @@ -453,11 +450,10 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) return 0; } -static int dib3000mb_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib3000mb_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dib3000_state* state = fe->demodulator_priv; - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t *cr; u16 tps_val; int inv_test1,inv_test2; @@ -484,25 +480,25 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, else inv_test2 = 2; - fep->inversion = + c->inversion = ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ? INVERSION_ON : INVERSION_OFF; - deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); + deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, c->inversion); switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { case DIB3000_CONSTELLATION_QPSK: deb_getf("QPSK "); - ofdm->constellation = QPSK; + c->modulation = QPSK; break; case DIB3000_CONSTELLATION_16QAM: deb_getf("QAM16 "); - ofdm->constellation = QAM_16; + c->modulation = QAM_16; break; case DIB3000_CONSTELLATION_64QAM: deb_getf("QAM64 "); - ofdm->constellation = QAM_64; + c->modulation = QAM_64; break; default: err("Unexpected constellation returned by TPS (%d)", tps_val); @@ -512,24 +508,24 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, if (rd(DIB3000MB_REG_TPS_HRCH)) { deb_getf("HRCH ON\n"); - cr = &ofdm->code_rate_LP; - ofdm->code_rate_HP = FEC_NONE; + cr = &c->code_rate_LP; + c->code_rate_HP = FEC_NONE; switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { case DIB3000_ALPHA_0: deb_getf("HIERARCHY_NONE "); - ofdm->hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; break; case DIB3000_ALPHA_1: deb_getf("HIERARCHY_1 "); - ofdm->hierarchy_information = HIERARCHY_1; + c->hierarchy = HIERARCHY_1; break; case DIB3000_ALPHA_2: deb_getf("HIERARCHY_2 "); - ofdm->hierarchy_information = HIERARCHY_2; + c->hierarchy = HIERARCHY_2; break; case DIB3000_ALPHA_4: deb_getf("HIERARCHY_4 "); - ofdm->hierarchy_information = HIERARCHY_4; + c->hierarchy = HIERARCHY_4; break; default: err("Unexpected ALPHA value returned by TPS (%d)", tps_val); @@ -540,9 +536,9 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); } else { deb_getf("HRCH OFF\n"); - cr = &ofdm->code_rate_HP; - ofdm->code_rate_LP = FEC_NONE; - ofdm->hierarchy_information = HIERARCHY_NONE; + cr = &c->code_rate_HP; + c->code_rate_LP = FEC_NONE; + c->hierarchy = HIERARCHY_NONE; tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); } @@ -577,19 +573,19 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { case DIB3000_GUARD_TIME_1_32: deb_getf("GUARD_INTERVAL_1_32 "); - ofdm->guard_interval = GUARD_INTERVAL_1_32; + c->guard_interval = GUARD_INTERVAL_1_32; break; case DIB3000_GUARD_TIME_1_16: deb_getf("GUARD_INTERVAL_1_16 "); - ofdm->guard_interval = GUARD_INTERVAL_1_16; + c->guard_interval = GUARD_INTERVAL_1_16; break; case DIB3000_GUARD_TIME_1_8: deb_getf("GUARD_INTERVAL_1_8 "); - ofdm->guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; break; case DIB3000_GUARD_TIME_1_4: deb_getf("GUARD_INTERVAL_1_4 "); - ofdm->guard_interval = GUARD_INTERVAL_1_4; + c->guard_interval = GUARD_INTERVAL_1_4; break; default: err("Unexpected Guard Time returned by TPS (%d)", tps_val); @@ -600,11 +596,11 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { case DIB3000_TRANSMISSION_MODE_2K: deb_getf("TRANSMISSION_MODE_2K "); - ofdm->transmission_mode = TRANSMISSION_MODE_2K; + c->transmission_mode = TRANSMISSION_MODE_2K; break; case DIB3000_TRANSMISSION_MODE_8K: deb_getf("TRANSMISSION_MODE_8K "); - ofdm->transmission_mode = TRANSMISSION_MODE_8K; + c->transmission_mode = TRANSMISSION_MODE_8K; break; default: err("unexpected transmission mode return by TPS (%d)", tps_val); @@ -701,9 +697,9 @@ static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe) return dib3000mb_fe_init(fe, 0); } -static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) +static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend *fe) { - return dib3000mb_set_frontend(fe, fep, 1); + return dib3000mb_set_frontend(fe, 1); } static void dib3000mb_release(struct dvb_frontend* fe) @@ -794,10 +790,9 @@ error: } static struct dvb_frontend_ops dib3000mb_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 3000M-B DVB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h index 16c526591f36..9dc235aa44b7 100644 --- a/drivers/media/dvb/frontends/dib3000mb_priv.h +++ b/drivers/media/dvb/frontends/dib3000mb_priv.h @@ -98,7 +98,7 @@ struct dib3000_state { int timing_offset; int timing_offset_comp_done; - fe_bandwidth_t last_tuned_bw; + u32 last_tuned_bw; u32 last_tuned_freq; }; diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 088e7fadbe3d..ffad181a9692 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -40,7 +40,7 @@ struct dib3000mc_state { u32 timf; - fe_bandwidth_t current_bandwidth; + u32 current_bandwidth; u16 dev_id; @@ -438,11 +438,14 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam) dib3000mc_write_word(state, reg, cfg[reg - 129]); } -static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq) +static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, + struct dtv_frontend_properties *ch, u16 seq) { u16 value; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0); + u32 bw = BANDWIDTH_TO_KHZ(ch->bandwidth_hz); + + dib3000mc_set_bandwidth(state, bw); + dib3000mc_set_timing(state, ch->transmission_mode, bw, 0); // if (boost) // dib3000mc_write_word(state, 100, (11 << 6) + 6); @@ -471,22 +474,22 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); - dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); + dib3000mc_set_impulse_noise(state, 0, ch->transmission_mode); value = 0; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; default: case TRANSMISSION_MODE_8K: value |= (1 << 7); break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; case GUARD_INTERVAL_1_16: value |= (1 << 5); break; case GUARD_INTERVAL_1_4: value |= (3 << 5); break; default: case GUARD_INTERVAL_1_8: value |= (2 << 5); break; } - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QPSK: value |= (0 << 3); break; case QAM_16: value |= (1 << 3); break; default: @@ -502,11 +505,11 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); value = 0; - if (ch->u.ofdm.hierarchy_information == 1) + if (ch->hierarchy == 1) value |= (1 << 4); if (1 == 1) value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; case FEC_3_4: value |= (3 << 1); break; case FEC_5_6: value |= (5 << 1); break; @@ -517,12 +520,12 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ dib3000mc_write_word(state, 181, value); // diversity synchro delay add 50% SFN margin - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; case TRANSMISSION_MODE_2K: default: value = 64; break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; case GUARD_INTERVAL_1_8: value *= 4; break; case GUARD_INTERVAL_1_4: value *= 8; break; @@ -540,27 +543,28 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_ msleep(30); - dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode); + dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->transmission_mode); } -static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan) +static int dib3000mc_autosearch_start(struct dvb_frontend *demod) { + struct dtv_frontend_properties *chan = &demod->dtv_property_cache; struct dib3000mc_state *state = demod->demodulator_priv; u16 reg; // u32 val; - struct dvb_frontend_parameters schan; + struct dtv_frontend_properties schan; schan = *chan; /* TODO what is that ? */ /* a channel for autosearch */ - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_2_3; - schan.u.ofdm.hierarchy_information = 0; + schan.transmission_mode = TRANSMISSION_MODE_8K; + schan.guard_interval = GUARD_INTERVAL_1_32; + schan.modulation = QAM_64; + schan.code_rate_HP = FEC_2_3; + schan.code_rate_LP = FEC_2_3; + schan.hierarchy = 0; dib3000mc_set_channel_cfg(state, &schan, 11); @@ -586,8 +590,9 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod) return 0; // still pending } -static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib3000mc_tune(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib3000mc_state *state = demod->demodulator_priv; // ** configure demod ** @@ -603,8 +608,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift } - dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); - if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { + dib3000mc_set_adp_cfg(state, (u8)ch->modulation); + if (ch->transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { @@ -613,7 +618,8 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parame } if (dib3000mc_read_word(state, 509) & 0x80) - dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); + dib3000mc_set_timing(state, ch->transmission_mode, + BANDWIDTH_TO_KHZ(ch->bandwidth_hz), 1); return 0; } @@ -626,87 +632,87 @@ struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master); -static int dib3000mc_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib3000mc_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib3000mc_state *state = fe->demodulator_priv; u16 tps = dib3000mc_read_word(state,458); fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = state->current_bandwidth; + fep->bandwidth_hz = state->current_bandwidth; switch ((tps >> 8) & 0x1) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; + case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break; } switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break; + case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break; + case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break; + case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 13) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; + case 0: fep->modulation = QPSK; break; + case 1: fep->modulation = QAM_16; break; case 2: - default: fep->u.ofdm.constellation = QAM_64; break; + default: fep->modulation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; + case 1: fep->code_rate_HP = FEC_1_2; break; + case 2: fep->code_rate_HP = FEC_2_3; break; + case 3: fep->code_rate_HP = FEC_3_4; break; + case 5: fep->code_rate_HP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + default: fep->code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; + case 1: fep->code_rate_LP = FEC_1_2; break; + case 2: fep->code_rate_LP = FEC_2_3; break; + case 3: fep->code_rate_LP = FEC_3_4; break; + case 5: fep->code_rate_LP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + default: fep->code_rate_LP = FEC_7_8; break; } return 0; } -static int dib3000mc_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib3000mc_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib3000mc_state *state = fe->demodulator_priv; - int ret; + int ret; dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + state->current_bandwidth = fep->bandwidth_hz; + dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz)); /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); msleep(100); } - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || + fep->guard_interval == GUARD_INTERVAL_AUTO || + fep->modulation == QAM_AUTO || + fep->code_rate_HP == FEC_AUTO) { int i = 1000, found; - dib3000mc_autosearch_start(fe, fep); + dib3000mc_autosearch_start(fe); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); @@ -716,14 +722,14 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, if (found == 0 || found == 1) return 0; // no channel found - dib3000mc_get_frontend(fe, fep); + dib3000mc_get_frontend(fe); } - ret = dib3000mc_tune(fe, fep); + ret = dib3000mc_tune(fe); /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; + return ret; } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -897,9 +903,9 @@ error: EXPORT_SYMBOL(dib3000mc_attach); static struct dvb_frontend_ops dib3000mc_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 3000MC/P", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index dbb76d75c932..148bf79236fb 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -38,7 +38,7 @@ struct dib7000m_state { u16 wbd_ref; u8 current_band; - fe_bandwidth_t current_bandwidth; + u32 current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; u32 timf_default; @@ -313,6 +313,9 @@ static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) { u32 timf; + if (!bw) + bw = 8000; + // store the current bandwidth for later use state->current_bandwidth = bw; @@ -742,8 +745,9 @@ static void dib7000m_update_timf(struct dib7000m_state *state) dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); } -static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000m_agc_startup(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000m_state *state = demod->demodulator_priv; u16 cfg_72 = dib7000m_read_word(state, 72); int ret = -1; @@ -832,28 +836,29 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ return ret; } -static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq) +static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_frontend_properties *ch, + u8 seq) { u16 value, est[4]; - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); /* nfft, guard, qam, alpha */ value = 0; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; case TRANSMISSION_MODE_4K: value |= (2 << 7); break; default: case TRANSMISSION_MODE_8K: value |= (1 << 7); break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; case GUARD_INTERVAL_1_16: value |= (1 << 5); break; case GUARD_INTERVAL_1_4: value |= (3 << 5); break; default: case GUARD_INTERVAL_1_8: value |= (2 << 5); break; } - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QPSK: value |= (0 << 3); break; case QAM_16: value |= (1 << 3); break; default: @@ -872,11 +877,11 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte value = 0; if (1 != 0) value |= (1 << 6); - if (ch->u.ofdm.hierarchy_information == 1) + if (ch->hierarchy == 1) value |= (1 << 4); if (1 == 1) value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; case FEC_3_4: value |= (3 << 1); break; case FEC_5_6: value |= (5 << 1); break; @@ -901,13 +906,13 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte dib7000m_write_word(state, 33, (0 << 4) | 0x5); /* P_dvsy_sync_wait */ - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; case TRANSMISSION_MODE_4K: value = 128; break; case TRANSMISSION_MODE_2K: default: value = 64; break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; case GUARD_INTERVAL_1_8: value *= 4; break; case GUARD_INTERVAL_1_4: value *= 8; break; @@ -925,7 +930,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte dib7000m_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ @@ -952,25 +957,26 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD); } -static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000m_autosearch_start(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000m_state *state = demod->demodulator_priv; - struct dvb_frontend_parameters schan; + struct dtv_frontend_properties schan; int ret = 0; u32 value, factor; schan = *ch; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; + schan.modulation = QAM_64; + schan.guard_interval = GUARD_INTERVAL_1_32; + schan.transmission_mode = TRANSMISSION_MODE_8K; + schan.code_rate_HP = FEC_2_3; + schan.code_rate_LP = FEC_3_4; + schan.hierarchy = 0; dib7000m_set_channel(state, &schan, 7); - factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); + factor = BANDWIDTH_TO_KHZ(schan.bandwidth_hz); if (factor >= 5000) factor = 1; else @@ -1027,8 +1033,9 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod) return dib7000m_autosearch_irq(state, 537); } -static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000m_tune(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000m_state *state = demod->demodulator_priv; int ret = 0; u16 value; @@ -1055,7 +1062,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet //dump_reg(state); /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ value = (6 << 8) | 0x80; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (7 << 12); break; case TRANSMISSION_MODE_4K: value |= (8 << 12); break; default: @@ -1065,7 +1072,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ value = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= 0x6; break; case TRANSMISSION_MODE_4K: value |= 0x7; break; default: @@ -1075,7 +1082,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ value = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= 0x6; break; case TRANSMISSION_MODE_4K: value |= 0x7; break; default: @@ -1087,7 +1094,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet if ((dib7000m_read_word(state, 535) >> 6) & 0x1) dib7000m_update_timf(state); - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); return ret; } @@ -1147,57 +1154,57 @@ static int dib7000m_identify(struct dib7000m_state *state) } -static int dib7000m_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib7000m_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000m_state *state = fe->demodulator_priv; u16 tps = dib7000m_read_word(state,480); fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = state->current_bandwidth; + fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth); switch ((tps >> 8) & 0x3) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + case 0: fep->transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: fep->transmission_mode = TRANSMISSION_MODE_8K; break; + /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + case 0: fep->guard_interval = GUARD_INTERVAL_1_32; break; + case 1: fep->guard_interval = GUARD_INTERVAL_1_16; break; + case 2: fep->guard_interval = GUARD_INTERVAL_1_8; break; + case 3: fep->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 14) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; + case 0: fep->modulation = QPSK; break; + case 1: fep->modulation = QAM_16; break; case 2: - default: fep->u.ofdm.constellation = QAM_64; break; + default: fep->modulation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; + case 1: fep->code_rate_HP = FEC_1_2; break; + case 2: fep->code_rate_HP = FEC_2_3; break; + case 3: fep->code_rate_HP = FEC_3_4; break; + case 5: fep->code_rate_HP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + default: fep->code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; + case 1: fep->code_rate_LP = FEC_1_2; break; + case 2: fep->code_rate_LP = FEC_2_3; break; + case 3: fep->code_rate_LP = FEC_3_4; break; + case 5: fep->code_rate_LP = FEC_5_6; break; case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + default: fep->code_rate_LP = FEC_7_8; break; } /* native interleaver: (dib7000m_read_word(state, 481) >> 5) & 0x1 */ @@ -1205,35 +1212,34 @@ static int dib7000m_get_frontend(struct dvb_frontend* fe, return 0; } -static int dib7000m_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib7000m_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000m_state *state = fe->demodulator_priv; int time, ret; - dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); + dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->bandwidth_hz)); if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); /* start up the AGC */ state->agc_state = 0; do { - time = dib7000m_agc_startup(fe, fep); + time = dib7000m_agc_startup(fe); if (time != -1) msleep(time); } while (time != -1); - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || + fep->guard_interval == GUARD_INTERVAL_AUTO || + fep->modulation == QAM_AUTO || + fep->code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000m_autosearch_start(fe, fep); + dib7000m_autosearch_start(fe); do { msleep(1); found = dib7000m_autosearch_is_irq(fe); @@ -1243,10 +1249,10 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, if (found == 0 || found == 1) return 0; // no channel found - dib7000m_get_frontend(fe, fep); + dib7000m_get_frontend(fe); } - ret = dib7000m_tune(fe, fep); + ret = dib7000m_tune(fe); /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); @@ -1430,9 +1436,9 @@ error: EXPORT_SYMBOL(dib7000m_attach); static struct dvb_frontend_ops dib7000m_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 7000MA/MB/PA/PB/MC", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index ce8534ff142e..5ceadc285b3a 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -70,6 +70,8 @@ struct dib7000p_state { u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; struct mutex i2c_buffer_lock; + + u8 input_mode_mpeg; }; enum dib7000p_power_mode { @@ -78,8 +80,11 @@ enum dib7000p_power_mode { DIB7000P_POWER_INTERFACE_ONLY, }; +/* dib7090 specific fonctions */ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); +static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode); +static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode); static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) { @@ -276,17 +281,23 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p dib7000p_write_word(state, 774, reg_774); dib7000p_write_word(state, 775, reg_775); dib7000p_write_word(state, 776, reg_776); - dib7000p_write_word(state, 899, reg_899); dib7000p_write_word(state, 1280, reg_1280); + if (state->version != SOC7090) + dib7000p_write_word(state, 899, reg_899); return 0; } static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no) { - u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909); + u16 reg_908 = 0, reg_909 = 0; u16 reg; + if (state->version != SOC7090) { + reg_908 = dib7000p_read_word(state, 908); + reg_909 = dib7000p_read_word(state, 909); + } + switch (no) { case DIBX000_SLOW_ADC_ON: if (state->version == SOC7090) { @@ -342,8 +353,10 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4; reg_908 |= (state->cfg.enable_current_mirror & 1) << 7; - dib7000p_write_word(state, 908, reg_908); - dib7000p_write_word(state, 909, reg_909); + if (state->version != SOC7090) { + dib7000p_write_word(state, 908, reg_908); + dib7000p_write_word(state, 909, reg_909); + } } static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) @@ -398,6 +411,24 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) } EXPORT_SYMBOL(dib7000p_set_wbd_ref); +int dib7000p_get_agc_values(struct dvb_frontend *fe, + u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd) +{ + struct dib7000p_state *state = fe->demodulator_priv; + + if (agc_global != NULL) + *agc_global = dib7000p_read_word(state, 394); + if (agc1 != NULL) + *agc1 = dib7000p_read_word(state, 392); + if (agc2 != NULL) + *agc2 = dib7000p_read_word(state, 393); + if (wbd != NULL) + *wbd = dib7000p_read_word(state, 397); + + return 0; +} +EXPORT_SYMBOL(dib7000p_get_agc_values); + static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; @@ -519,7 +550,7 @@ static u16 dib7000p_defaults[] = { // auto search configuration 3, 2, 0x0004, - 0x1000, + (1<<3)|(1<<11)|(1<<12)|(1<<13), 0x0814, /* Equal Lock */ 12, 6, @@ -595,13 +626,6 @@ static u16 dib7000p_defaults[] = { 1, 235, 0x0062, - 2, 901, - 0x0006, - (3 << 10) | (1 << 6), - - 1, 905, - 0x2c8e, - 0, }; @@ -618,15 +642,18 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_write_word(state, 770, 0xffff); dib7000p_write_word(state, 771, 0xffff); dib7000p_write_word(state, 772, 0x001f); - dib7000p_write_word(state, 898, 0x0003); dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3))); dib7000p_write_word(state, 770, 0); dib7000p_write_word(state, 771, 0); dib7000p_write_word(state, 772, 0); - dib7000p_write_word(state, 898, 0); dib7000p_write_word(state, 1280, 0); + if (state->version != SOC7090) { + dib7000p_write_word(state, 898, 0x0003); + dib7000p_write_word(state, 898, 0); + } + /* default */ dib7000p_reset_pll(state); @@ -640,7 +667,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ - dib7000p_write_word(state, 273, (1<<6) | 30); + dib7000p_write_word(state, 273, (0<<6) | 30); } if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) dprintk("OUTPUT_MODE could not be reset."); @@ -655,7 +682,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_set_bandwidth(state, 8000); if (state->version == SOC7090) { - dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ + dib7000p_write_word(state, 36, 0x0755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ } else { if (state->cfg.tuner_is_baseband) dib7000p_write_word(state, 36, 0x0755); @@ -664,6 +691,11 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) } dib7000p_write_tab(state, dib7000p_defaults); + if (state->version != SOC7090) { + dib7000p_write_word(state, 901, 0x0006); + dib7000p_write_word(state, 902, (3 << 10) | (1 << 6)); + dib7000p_write_word(state, 905, 0x2c8e); + } dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); @@ -780,8 +812,9 @@ static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) } } -static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000p_agc_startup(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000p_state *state = demod->demodulator_priv; int ret = -1; u8 *agc_state = &state->agc_state; @@ -904,15 +937,16 @@ u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) } EXPORT_SYMBOL(dib7000p_ctrl_timf); -static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) +static void dib7000p_set_channel(struct dib7000p_state *state, + struct dtv_frontend_properties *ch, u8 seq) { u16 value, est[4]; - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); /* nfft, guard, qam, alpha */ value = 0; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; @@ -924,7 +958,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value |= (1 << 7); break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; @@ -939,7 +973,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value |= (2 << 5); break; } - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QPSK: value |= (0 << 3); break; @@ -970,11 +1004,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value = 0; if (1 != 0) value |= (1 << 6); - if (ch->u.ofdm.hierarchy_information == 1) + if (ch->hierarchy == 1) value |= (1 << 4); if (1 == 1) value |= 1; - switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { + switch ((ch->hierarchy == 0 || 1 == 1) ? ch->code_rate_HP : ch->code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; @@ -1001,7 +1035,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte dib7000p_write_word(state, 33, 0x0005); /* P_dvsy_sync_wait */ - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; @@ -1013,7 +1047,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte value = 64; break; } - switch (ch->u.ofdm.guard_interval) { + switch (ch->guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; @@ -1034,11 +1068,11 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; /* deactive the possibility of diversity reception if extended interleaver */ - state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; + state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K; dib7000p_set_diversity_in(&state->demod, state->div_state); /* channel estimation fine configuration */ - switch (ch->u.ofdm.constellation) { + switch (ch->modulation) { case QAM_64: est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ @@ -1062,27 +1096,31 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte dib7000p_write_word(state, 187 + value, est[value]); } -static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000p_autosearch_start(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000p_state *state = demod->demodulator_priv; - struct dvb_frontend_parameters schan; + struct dtv_frontend_properties schan; u32 value, factor; u32 internal = dib7000p_get_internal_freq(state); schan = *ch; - schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; + schan.modulation = QAM_64; + schan.guard_interval = GUARD_INTERVAL_1_32; + schan.transmission_mode = TRANSMISSION_MODE_8K; + schan.code_rate_HP = FEC_2_3; + schan.code_rate_LP = FEC_3_4; + schan.hierarchy = 0; dib7000p_set_channel(state, &schan, 7); - factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth); - if (factor >= 5000) - factor = 1; - else + factor = BANDWIDTH_TO_KHZ(ch->bandwidth_hz); + if (factor >= 5000) { + if (state->version == SOC7090) + factor = 2; + else + factor = 1; + } else factor = 6; value = 30 * internal * factor; @@ -1205,8 +1243,9 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 dib7000p_write_word(state, 143, 0); } -static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) +static int dib7000p_tune(struct dvb_frontend *demod) { + struct dtv_frontend_properties *ch = &demod->dtv_property_cache; struct dib7000p_state *state = demod->demodulator_priv; u16 tmp = 0; @@ -1239,7 +1278,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: tmp |= (2 << 12); break; @@ -1255,7 +1294,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: tmp |= 0x6; break; @@ -1271,7 +1310,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); - switch (ch->u.ofdm.transmission_mode) { + switch (ch->transmission_mode) { case TRANSMISSION_MODE_2K: tmp |= 0x6; break; @@ -1303,9 +1342,9 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet } if (state->cfg.spur_protect) - dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz)); return 0; } @@ -1323,7 +1362,7 @@ static int dib7000p_sleep(struct dvb_frontend *demod) { struct dib7000p_state *state = demod->demodulator_priv; if (state->version == SOC7090) - return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); + return dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); } @@ -1345,93 +1384,94 @@ static int dib7000p_identify(struct dib7000p_state *st) return 0; } -static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7000p_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000p_state *state = fe->demodulator_priv; u16 tps = dib7000p_read_word(state, 463); fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); + fep->bandwidth_hz = BANDWIDTH_TO_HZ(state->current_bandwidth); switch ((tps >> 8) & 0x3) { case 0: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + fep->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: - fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + fep->transmission_mode = TRANSMISSION_MODE_8K; break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + /* case 2: fep->transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { case 0: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + fep->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + fep->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + fep->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + fep->guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 14) & 0x3) { case 0: - fep->u.ofdm.constellation = QPSK; + fep->modulation = QPSK; break; case 1: - fep->u.ofdm.constellation = QAM_16; + fep->modulation = QAM_16; break; case 2: default: - fep->u.ofdm.constellation = QAM_64; + fep->modulation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 13) & 0x1 == hrch is used, (tps >> 10) & 0x7 == alpha */ - fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fep->hierarchy = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { case 1: - fep->u.ofdm.code_rate_HP = FEC_1_2; + fep->code_rate_HP = FEC_1_2; break; case 2: - fep->u.ofdm.code_rate_HP = FEC_2_3; + fep->code_rate_HP = FEC_2_3; break; case 3: - fep->u.ofdm.code_rate_HP = FEC_3_4; + fep->code_rate_HP = FEC_3_4; break; case 5: - fep->u.ofdm.code_rate_HP = FEC_5_6; + fep->code_rate_HP = FEC_5_6; break; case 7: default: - fep->u.ofdm.code_rate_HP = FEC_7_8; + fep->code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { case 1: - fep->u.ofdm.code_rate_LP = FEC_1_2; + fep->code_rate_LP = FEC_1_2; break; case 2: - fep->u.ofdm.code_rate_LP = FEC_2_3; + fep->code_rate_LP = FEC_2_3; break; case 3: - fep->u.ofdm.code_rate_LP = FEC_3_4; + fep->code_rate_LP = FEC_3_4; break; case 5: - fep->u.ofdm.code_rate_LP = FEC_5_6; + fep->code_rate_LP = FEC_5_6; break; case 7: default: - fep->u.ofdm.code_rate_LP = FEC_7_8; + fep->code_rate_LP = FEC_7_8; break; } @@ -1440,36 +1480,36 @@ static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa return 0; } -static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib7000p_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct dib7000p_state *state = fe->demodulator_priv; int time, ret; - if (state->version == SOC7090) { + if (state->version == SOC7090) dib7090_set_diversity_in(fe, 0); - dib7090_set_output_mode(fe, OUTMODE_HIGH_Z); - } else + else dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); + fe->ops.tuner_ops.set_params(fe); /* start up the AGC */ state->agc_state = 0; do { - time = dib7000p_agc_startup(fe, fep); + time = dib7000p_agc_startup(fe); if (time != -1) msleep(time); } while (time != -1); - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (fep->transmission_mode == TRANSMISSION_MODE_AUTO || + fep->guard_interval == GUARD_INTERVAL_AUTO || fep->modulation == QAM_AUTO || fep->code_rate_HP == FEC_AUTO) { int i = 800, found; - dib7000p_autosearch_start(fe, fep); + dib7000p_autosearch_start(fe); do { msleep(1); found = dib7000p_autosearch_is_irq(fe); @@ -1479,15 +1519,19 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa if (found == 0 || found == 1) return 0; - dib7000p_get_frontend(fe, fep); + dib7000p_get_frontend(fe); } - ret = dib7000p_tune(fe, fep); + ret = dib7000p_tune(fe); /* make this a config parameter */ - if (state->version == SOC7090) + if (state->version == SOC7090) { dib7090_set_output_mode(fe, state->cfg.output_mode); - else + if (state->cfg.enMpegOutput == 0) { + dib7090_setDibTxMux(state, MPEG_ON_DIBTX); + dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); + } + } else dib7000p_set_output_mode(state, state->cfg.output_mode); return ret; @@ -1831,7 +1875,8 @@ static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg m return num; } -int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address) +static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num, u16 apb_address) { struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); u16 word; @@ -1933,10 +1978,10 @@ static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] apb_address = 915; break; case 0x27: - apb_address = 916; + apb_address = 917; break; case 0x28: - apb_address = 917; + apb_address = 916; break; case 0x1d: i = ((dib7000p_read_word(state, 72) >> 12) & 0x3); @@ -2031,12 +2076,7 @@ static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) { - u8 index_buf; - u16 rx_copy_buf[22]; - dprintk("Configure DibStream Tx"); - for (index_buf = 0; index_buf < 22; index_buf++) - rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf); dib7000p_write_word(state, 1615, 1); dib7000p_write_word(state, 1603, P_Kin); @@ -2048,9 +2088,6 @@ static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout dib7000p_write_word(state, 1612, syncSize); dib7000p_write_word(state, 1615, 0); - for (index_buf = 0; index_buf < 22; index_buf++) - dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]); - return 0; } @@ -2077,109 +2114,121 @@ static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout return 0; } -static int dib7090_enDivOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable Diversity on host bus"); - reg = (1 << 8) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); -} - -static int dib7090_enAdcOnHostBus(struct dib7000p_state *state) -{ - u16 reg; - - dprintk("Enable ADC on host bus"); - reg = (1 << 7) | (1 << 5); - dib7000p_write_word(state, 1288, reg); - - return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); -} - -static int dib7090_enMpegOnHostBus(struct dib7000p_state *state) +static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff) { - u16 reg; - - dprintk("Enable Mpeg on host bus"); - reg = (1 << 9) | (1 << 5); - dib7000p_write_word(state, 1288, reg); + u16 reg_1287 = dib7000p_read_word(state, 1287); - return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); -} + switch (onoff) { + case 1: + reg_1287 &= ~(1<<7); + break; + case 0: + reg_1287 |= (1<<7); + break; + } -static int dib7090_enMpegInput(struct dib7000p_state *state) -{ - dprintk("Enable Mpeg input"); - return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ + dib7000p_write_word(state, 1287, reg_1287); } -static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) +static void dib7090_configMpegMux(struct dib7000p_state *state, + u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) { - u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1); - dprintk("Enable Mpeg mux"); - dib7000p_write_word(state, 1287, reg); - reg &= ~(1 << 7); - dib7000p_write_word(state, 1287, reg); + dib7090_enMpegMux(state, 0); - reg = (1 << 4); - dib7000p_write_word(state, 1288, reg); + /* If the input mode is MPEG do not divide the serial clock */ + if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) + enSerialClkDiv2 = 0; - return 0; + dib7000p_write_word(state, 1287, ((pulseWidth & 0x1f) << 2) + | ((enSerialMode & 0x1) << 1) + | (enSerialClkDiv2 & 0x1)); + + dib7090_enMpegMux(state, 1); } -static int dib7090_disableMpegMux(struct dib7000p_state *state) +static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode) { - u16 reg; - - dprintk("Disable Mpeg mux"); - dib7000p_write_word(state, 1288, 0); - - reg = dib7000p_read_word(state, 1287); - reg &= ~(1 << 7); - dib7000p_write_word(state, 1287, reg); + u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 7); - return 0; + switch (mode) { + case MPEG_ON_DIBTX: + dprintk("SET MPEG ON DIBSTREAM TX"); + dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); + reg_1288 |= (1<<9); + break; + case DIV_ON_DIBTX: + dprintk("SET DIV_OUT ON DIBSTREAM TX"); + dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); + reg_1288 |= (1<<8); + break; + case ADC_ON_DIBTX: + dprintk("SET ADC_OUT ON DIBSTREAM TX"); + dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); + reg_1288 |= (1<<7); + break; + default: + break; + } + dib7000p_write_word(state, 1288, reg_1288); } -static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode) +static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode) { - struct dib7000p_state *state = fe->demodulator_priv; + u16 reg_1288 = dib7000p_read_word(state, 1288) & ~(0x7 << 4); switch (mode) { - case INPUT_MODE_DIVERSITY: - dprintk("Enable diversity INPUT"); - dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + case DEMOUT_ON_HOSTBUS: + dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); + dib7090_enMpegMux(state, 0); + reg_1288 |= (1<<6); + break; + case DIBTX_ON_HOSTBUS: + dprintk("SET DIBSTREAM TX ON HOST BUS"); + dib7090_enMpegMux(state, 0); + reg_1288 |= (1<<5); break; - case INPUT_MODE_MPEG: - dprintk("Enable Mpeg INPUT"); - dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ + case MPEG_ON_HOSTBUS: + dprintk("SET MPEG MUX ON HOST BUS"); + reg_1288 |= (1<<4); break; - case INPUT_MODE_OFF: default: - dprintk("Disable INPUT"); - dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0); break; } - return 0; + dib7000p_write_word(state, 1288, reg_1288); } -static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) +int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) { + struct dib7000p_state *state = fe->demodulator_priv; + u16 reg_1287; + switch (onoff) { - case 0: /* only use the internal way - not the diversity input */ - dib7090_set_input_mode(fe, INPUT_MODE_MPEG); - break; - case 1: /* both ways */ - case 2: /* only the diversity input */ - dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY); - break; + case 0: /* only use the internal way - not the diversity input */ + dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__); + dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); + + /* Do not divide the serial clock of MPEG MUX */ + /* in SERIAL MODE in case input mode MPEG is used */ + reg_1287 = dib7000p_read_word(state, 1287); + /* enSerialClkDiv2 == 1 ? */ + if ((reg_1287 & 0x1) == 1) { + /* force enSerialClkDiv2 = 0 */ + reg_1287 &= ~0x1; + dib7000p_write_word(state, 1287, reg_1287); + } + state->input_mode_mpeg = 1; + break; + case 1: /* both ways */ + case 2: /* only the diversity input */ + dprintk("%s ON : Enable diversity INPUT", __func__); + dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + state->input_mode_mpeg = 0; + break; } + dib7000p_set_diversity_in(&state->demod, onoff); return 0; } @@ -2204,69 +2253,63 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_SERIAL: if (prefer_mpeg_mux_use) { - dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux"); - dib7090_enMpegOnHostBus(state); - dib7090_enMpegInput(state); - if (state->cfg.enMpegOutput == 1) - dib7090_enMpegMux(state, 3, 1, 1); - - } else { /* Use Smooth block */ - dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (2 << 6) | (0 << 1); + dprintk("setting output mode TS_SERIAL using Mpeg Mux"); + dib7090_configMpegMux(state, 3, 1, 1); + dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else {/* Use Smooth block */ + dprintk("setting output mode TS_SERIAL using Smooth bloc"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (2<<6) | (0 << 1); } break; case OUTMODE_MPEG2_PAR_GATED_CLK: if (prefer_mpeg_mux_use) { - dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); - dib7090_enMpegOnHostBus(state); - dib7090_enMpegInput(state); - if (state->cfg.enMpegOutput == 1) - dib7090_enMpegMux(state, 2, 0, 0); - } else { /* Use Smooth block */ - dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (0 << 6); + dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dib7090_configMpegMux(state, 2, 0, 0); + dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else { /* Use Smooth block */ + dprintk("setting output mode TS_PARALLEL_GATED using Smooth block"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (0<<6); } break; case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ - dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (1 << 6); + dprintk("setting output mode TS_PARALLEL_CONT using Smooth block"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (1<<6); break; case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ - dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block"); - dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); - outreg |= (5 << 6); + dprintk("setting output mode TS_FIFO using Smooth block"); + dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (5<<6); smo_mode |= (3 << 1); fifo_threshold = 512; break; case OUTMODE_DIVERSITY: - dprintk("Sip 7090P setting output mode MODE_DIVERSITY"); - dib7090_disableMpegMux(state); - dib7090_enDivOnHostBus(state); + dprintk("setting output mode MODE_DIVERSITY"); + dib7090_setDibTxMux(state, DIV_ON_DIBTX); + dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; case OUTMODE_ANALOG_ADC: - dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC"); - dib7090_enAdcOnHostBus(state); + dprintk("setting output mode MODE_ANALOG_ADC"); + dib7090_setDibTxMux(state, ADC_ON_DIBTX); + dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; } + if (mode != OUTMODE_HIGH_Z) + outreg |= (1 << 10); if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5); ret |= dib7000p_write_word(state, 235, smo_mode); ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ - ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */ + ret |= dib7000p_write_word(state, 1286, outreg); return ret; } @@ -2296,13 +2339,6 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) } EXPORT_SYMBOL(dib7090_tuner_sleep); -int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - dprintk("AGC restart callback: %d", restart); - return 0; -} -EXPORT_SYMBOL(dib7090_agc_restart); - int dib7090_get_adc_power(struct dvb_frontend *fe) { return dib7000p_get_adc_power(fe); @@ -2391,9 +2427,9 @@ error: EXPORT_SYMBOL(dib7000p_attach); static struct dvb_frontend_ops dib7000p_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 7000PC", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 0179f9474bac..b61b03a6e1ed 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -56,11 +56,12 @@ extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw); extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf); -extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart); extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff); extern int dib7090_get_adc_power(struct dvb_frontend *fe); extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe); extern int dib7090_slave_reset(struct dvb_frontend *fe); +extern int dib7000p_get_agc_values(struct dvb_frontend *fe, + u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) { @@ -122,12 +123,6 @@ static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) return 0; } -static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); @@ -151,6 +146,13 @@ static inline int dib7090_slave_reset(struct dvb_frontend *fe) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } + +static inline int dib7000p_get_agc_values(struct dvb_frontend *fe, + u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index fe284d5292f5..9ca34f495009 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -81,11 +81,15 @@ struct dib8000_state { u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; struct mutex i2c_buffer_lock; + u8 input_mode_mpeg; + + u16 tuner_enable; + struct i2c_adapter dib8096p_tuner_adap; }; enum dib8000_power_mode { - DIB8000M_POWER_ALL = 0, - DIB8000M_POWER_INTERFACE_ONLY, + DIB8000_POWER_ALL = 0, + DIB8000_POWER_INTERFACE_ONLY, }; static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) @@ -428,20 +432,31 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow /* by default everything is going to be powered off */ u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, + reg_1280; + + if (state->revision != 0x8090) reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; + else + reg_1280 = (dib8000_read_word(state, 1280) & 0x707f) | 0x8f80; /* now, depending on the requested mode, we power on */ switch (mode) { /* power up everything in the demod */ - case DIB8000M_POWER_ALL: + case DIB8000_POWER_ALL: reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0000; reg_900 &= 0xfffc; - reg_1280 &= 0x00ff; + if (state->revision != 0x8090) + reg_1280 &= 0x00ff; + else + reg_1280 &= 0x707f; break; - case DIB8000M_POWER_INTERFACE_ONLY: - reg_1280 &= 0x00ff; + case DIB8000_POWER_INTERFACE_ONLY: + if (state->revision != 0x8090) + reg_1280 &= 0x00ff; + else + reg_1280 &= 0xfa7b; break; } @@ -453,19 +468,67 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow dib8000_write_word(state, 1280, reg_1280); } +static int dib8000_init_sdram(struct dib8000_state *state) +{ + u16 reg = 0; + dprintk("Init sdram"); + + reg = dib8000_read_word(state, 274)&0xfff0; + /* P_dintlv_delay_ram = 7 because of MobileSdram */ + dib8000_write_word(state, 274, reg | 0x7); + + dib8000_write_word(state, 1803, (7<<2)); + + reg = dib8000_read_word(state, 1280); + /* force restart P_restart_sdram */ + dib8000_write_word(state, 1280, reg | (1<<2)); + + /* release restart P_restart_sdram */ + dib8000_write_word(state, 1280, reg); + + return 0; +} + static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) { int ret = 0; - u16 reg_907 = dib8000_read_word(state, 907), reg_908 = dib8000_read_word(state, 908); + u16 reg, reg_907 = dib8000_read_word(state, 907); + u16 reg_908 = dib8000_read_word(state, 908); switch (no) { case DIBX000_SLOW_ADC_ON: - reg_908 |= (1 << 1) | (1 << 0); - ret |= dib8000_write_word(state, 908, reg_908); - reg_908 &= ~(1 << 1); + if (state->revision != 0x8090) { + reg_908 |= (1 << 1) | (1 << 0); + ret |= dib8000_write_word(state, 908, reg_908); + reg_908 &= ~(1 << 1); + } else { + reg = dib8000_read_word(state, 1925); + /* en_slowAdc = 1 & reset_sladc = 1 */ + dib8000_write_word(state, 1925, reg | + (1<<4) | (1<<2)); + + /* read acces to make it works... strange ... */ + reg = dib8000_read_word(state, 1925); + msleep(20); + /* en_slowAdc = 1 & reset_sladc = 0 */ + dib8000_write_word(state, 1925, reg & ~(1<<4)); + + reg = dib8000_read_word(state, 921) & ~((0x3 << 14) + | (0x3 << 12)); + /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; + (Vin2 = Vcm) */ + dib8000_write_word(state, 921, reg | (1 << 14) + | (3 << 12)); + } break; case DIBX000_SLOW_ADC_OFF: + if (state->revision == 0x8090) { + reg = dib8000_read_word(state, 1925); + /* reset_sladc = 1 en_slowAdc = 0 */ + dib8000_write_word(state, 1925, + (reg & ~(1<<2)) | (1<<4)); + } reg_908 |= (1 << 1) | (1 << 0); break; @@ -521,7 +584,12 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) static int dib8000_sad_calib(struct dib8000_state *state) { -/* internal */ + if (state->revision == 0x8090) { + dprintk("%s: the sad calibration is not needed for the dib8096P", + __func__); + return 0; + } + /* internal */ dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096 @@ -546,48 +614,129 @@ EXPORT_SYMBOL(dib8000_set_wbd_ref); static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) { dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); - dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); /* P_sec_len */ - dib8000_write_word(state, 24, (u16) ((bw->internal * 1000) & 0xffff)); + if (state->revision != 0x8090) { + dib8000_write_word(state, 23, + (u16) (((bw->internal * 1000) >> 16) & 0xffff)); + dib8000_write_word(state, 24, + (u16) ((bw->internal * 1000) & 0xffff)); + } else { + dib8000_write_word(state, 23, (u16) (((bw->internal / 2 * 1000) >> 16) & 0xffff)); + dib8000_write_word(state, 24, + (u16) ((bw->internal / 2 * 1000) & 0xffff)); + } dib8000_write_word(state, 27, (u16) ((bw->ifreq >> 16) & 0x01ff)); dib8000_write_word(state, 28, (u16) (bw->ifreq & 0xffff)); dib8000_write_word(state, 26, (u16) ((bw->ifreq >> 25) & 0x0003)); - dib8000_write_word(state, 922, bw->sad_cfg); + if (state->revision != 0x8090) + dib8000_write_word(state, 922, bw->sad_cfg); } static void dib8000_reset_pll(struct dib8000_state *state) { const struct dibx000_bandwidth_config *pll = state->cfg.pll; - u16 clk_cfg1; - - // clk_cfg0 - dib8000_write_word(state, 901, (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); - - // clk_cfg1 - clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | - (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | - (pll->pll_range << 1) | (pll->pll_reset << 0); - - dib8000_write_word(state, 902, clk_cfg1); - clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); - dib8000_write_word(state, 902, clk_cfg1); - - dprintk("clk_cfg1: 0x%04x", clk_cfg1); /* 0x507 1 0 1 000 0 0 11 1 */ - - /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ - if (state->cfg.pll->ADClkSrc == 0) - dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | - (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); - else if (state->cfg.refclksel != 0) - dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | - ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | - (pll->ADClkSrc << 7) | (0 << 1)); - else - dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); + u16 clk_cfg1, reg; + + if (state->revision != 0x8090) { + dib8000_write_word(state, 901, + (pll->pll_prediv << 8) | (pll->pll_ratio << 0)); + + clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | + (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | + (1 << 3) | (pll->pll_range << 1) | + (pll->pll_reset << 0); + + dib8000_write_word(state, 902, clk_cfg1); + clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); + dib8000_write_word(state, 902, clk_cfg1); + + dprintk("clk_cfg1: 0x%04x", clk_cfg1); + + /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ + if (state->cfg.pll->ADClkSrc == 0) + dib8000_write_word(state, 904, + (0 << 15) | (0 << 12) | (0 << 10) | + (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + else if (state->cfg.refclksel != 0) + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | + ((state->cfg.refclksel & 0x3) << 10) | + (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + else + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | + (3 << 10) | (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); + } else { + dib8000_write_word(state, 1856, (!pll->pll_reset<<13) | + (pll->pll_range<<12) | (pll->pll_ratio<<6) | + (pll->pll_prediv)); + + reg = dib8000_read_word(state, 1857); + dib8000_write_word(state, 1857, reg|(!pll->pll_bypass<<15)); + + reg = dib8000_read_word(state, 1858); /* Force clk out pll /2 */ + dib8000_write_word(state, 1858, reg | 1); + + dib8000_write_word(state, 904, (pll->modulo << 8)); + } dib8000_reset_pll_common(state, pll); } +int dib8000_update_pll(struct dvb_frontend *fe, + struct dibx000_bandwidth_config *pll) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856); + u8 loopdiv, prediv; + u32 internal, xtal; + + /* get back old values */ + prediv = reg_1856 & 0x3f; + loopdiv = (reg_1856 >> 6) & 0x3f; + + if ((pll != NULL) && (pll->pll_prediv != prediv || + pll->pll_ratio != loopdiv)) { + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); + reg_1856 &= 0xf000; + reg_1857 = dib8000_read_word(state, 1857); + /* disable PLL */ + dib8000_write_word(state, 1857, reg_1857 & ~(1 << 15)); + + dib8000_write_word(state, 1856, reg_1856 | + ((pll->pll_ratio & 0x3f) << 6) | + (pll->pll_prediv & 0x3f)); + + /* write new system clk into P_sec_len */ + internal = dib8000_read32(state, 23) / 1000; + dprintk("Old Internal = %d", internal); + xtal = 2 * (internal / loopdiv) * prediv; + internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio; + dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000); + dprintk("New Internal = %d", internal); + + dib8000_write_word(state, 23, + (u16) (((internal / 2) >> 16) & 0xffff)); + dib8000_write_word(state, 24, (u16) ((internal / 2) & 0xffff)); + /* enable PLL */ + dib8000_write_word(state, 1857, reg_1857 | (1 << 15)); + + while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1) + dprintk("Waiting for PLL to lock"); + + /* verify */ + reg_1856 = dib8000_read_word(state, 1856); + dprintk("PLL Updated with prediv = %d and loopdiv = %d", + reg_1856&0x3f, (reg_1856>>6)&0x3f); + + return 0; + } + return -EINVAL; +} +EXPORT_SYMBOL(dib8000_update_pll); + + static int dib8000_reset_gpio(struct dib8000_state *st) { /* reset the GPIOs */ @@ -721,9 +870,6 @@ static const u16 dib8000_defaults[] = { (3 << 5) | /* P_ctrl_pre_freq_step=3 */ (1 << 0), /* P_pre_freq_win_len=1 */ - 1, 903, - (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) - 0, }; @@ -740,7 +886,8 @@ static u16 dib8000_identify(struct i2c_device *client) } value = dib8000_i2c_read16(client, 897); - if (value != 0x8000 && value != 0x8001 && value != 0x8002) { + if (value != 0x8000 && value != 0x8001 && + value != 0x8002 && value != 0x8090) { dprintk("wrong Device ID (%x)", value); return 0; } @@ -755,6 +902,9 @@ static u16 dib8000_identify(struct i2c_device *client) case 0x8002: dprintk("found DiB8000C"); break; + case 0x8090: + dprintk("found DiB8096P"); + break; } return value; } @@ -763,17 +913,19 @@ static int dib8000_reset(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; - dib8000_write_word(state, 1287, 0x0003); /* sram lead in, rdy */ - if ((state->revision = dib8000_identify(&state->i2c)) == 0) return -EINVAL; + /* sram lead in, rdy */ + if (state->revision != 0x8090) + dib8000_write_word(state, 1287, 0x0003); + if (state->revision == 0x8000) dprintk("error : dib8000 MA not supported"); dibx000_reset_i2c_master(&state->i2c_master); - dib8000_set_power_mode(state, DIB8000M_POWER_ALL); + dib8000_set_power_mode(state, DIB8000_POWER_ALL); /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ dib8000_set_adc_state(state, DIBX000_VBG_ENABLE); @@ -782,8 +934,10 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_write_word(state, 770, 0xffff); dib8000_write_word(state, 771, 0xffff); dib8000_write_word(state, 772, 0xfffc); - dib8000_write_word(state, 898, 0x000c); // sad - dib8000_write_word(state, 1280, 0x004d); + if (state->revision == 0x8090) + dib8000_write_word(state, 1280, 0x0045); + else + dib8000_write_word(state, 1280, 0x004d); dib8000_write_word(state, 1281, 0x000c); dib8000_write_word(state, 770, 0x0000); @@ -794,19 +948,25 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_write_word(state, 1281, 0x0000); /* drives */ - if (state->cfg.drives) - dib8000_write_word(state, 906, state->cfg.drives); - else { - dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); - dib8000_write_word(state, 906, 0x2d98); // min drive SDRAM - not optimal - adjust + if (state->revision != 0x8090) { + if (state->cfg.drives) + dib8000_write_word(state, 906, state->cfg.drives); + else { + dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); + /* min drive SDRAM - not optimal - adjust */ + dib8000_write_word(state, 906, 0x2d98); + } } dib8000_reset_pll(state); + if (state->revision != 0x8090) + dib8000_write_word(state, 898, 0x0004); if (dib8000_reset_gpio(state) != 0) dprintk("GPIO reset was not successful."); - if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0) + if ((state->revision != 0x8090) && + (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) dprintk("OUTPUT_MODE could not be resetted."); state->current_agc = NULL; @@ -832,6 +992,8 @@ static int dib8000_reset(struct dvb_frontend *fe) l = *n++; } } + if (state->revision != 0x8090) + dib8000_write_word(state, 903, (0 << 4) | 2); state->isdbt_cfg_loaded = 0; //div_cfg override for special configs @@ -844,10 +1006,12 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_set_bandwidth(fe, 6000); dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); - dib8000_sad_calib(state); - dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + if (state->revision != 0x8090) { + dib8000_sad_calib(state); + dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); + } - dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); return 0; } @@ -879,6 +1043,8 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) { struct dibx000_agc_config *agc = NULL; int i; + u16 reg; + if (state->current_band == band && state->current_agc != NULL) return 0; state->current_band = band; @@ -914,6 +1080,12 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) dib8000_write_word(state, 106, state->wbd_ref); else // use default dib8000_write_word(state, 106, agc->wbd_ref); + + if (state->revision == 0x8090) { + reg = dib8000_read_word(state, 922) & (0x3 << 2); + dib8000_write_word(state, 922, reg | (agc->wbd_sel << 2)); + } + dib8000_write_word(state, 107, (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); dib8000_write_word(state, 108, agc->agc1_max); dib8000_write_word(state, 109, agc->agc1_min); @@ -925,7 +1097,10 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) dib8000_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); dib8000_write_word(state, 75, agc->agc1_pt3); - dib8000_write_word(state, 923, (dib8000_read_word(state, 923) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); /*LB : 929 -> 923 */ + if (state->revision != 0x8090) + dib8000_write_word(state, 923, + (dib8000_read_word(state, 923) & 0xffe3) | + (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); return 0; } @@ -968,14 +1143,30 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 0; + u16 reg, upd_demod_gain_period = 0x8000; switch (*tune_state) { case CT_AGC_START: // set power-up level: interf+analog+AGC - dib8000_set_adc_state(state, DIBX000_ADC_ON); + if (state->revision != 0x8090) + dib8000_set_adc_state(state, DIBX000_ADC_ON); + else { + dib8000_set_power_mode(state, DIB8000_POWER_ALL); + + reg = dib8000_read_word(state, 1947)&0xff00; + dib8000_write_word(state, 1946, + upd_demod_gain_period & 0xFFFF); + /* bit 14 = enDemodGain */ + dib8000_write_word(state, 1947, reg | (1<<14) | + ((upd_demod_gain_period >> 16) & 0xFF)); + + /* enable adc i & q */ + reg = dib8000_read_word(state, 1920); + dib8000_write_word(state, 1920, (reg | 0x3) & + (~(1 << 7))); + } if (dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))) != 0) { *tune_state = CT_AGC_STOP; @@ -1026,6 +1217,579 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) } +static void dib8096p_host_bus_drive(struct dib8000_state *state, u8 drive) +{ + u16 reg; + + drive &= 0x7; + + /* drive host bus 2, 3, 4 */ + reg = dib8000_read_word(state, 1798) & + ~(0x7 | (0x7 << 6) | (0x7 << 12)); + reg |= (drive<<12) | (drive<<6) | drive; + dib8000_write_word(state, 1798, reg); + + /* drive host bus 5,6 */ + reg = dib8000_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive<<8) | (drive<<2); + dib8000_write_word(state, 1799, reg); + + /* drive host bus 7, 8, 9 */ + reg = dib8000_read_word(state, 1800) & + ~(0x7 | (0x7 << 6) | (0x7 << 12)); + reg |= (drive<<12) | (drive<<6) | drive; + dib8000_write_word(state, 1800, reg); + + /* drive host bus 10, 11 */ + reg = dib8000_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive<<8) | (drive<<2); + dib8000_write_word(state, 1801, reg); + + /* drive host bus 12, 13, 14 */ + reg = dib8000_read_word(state, 1802) & + ~(0x7 | (0x7 << 6) | (0x7 << 12)); + reg |= (drive<<12) | (drive<<6) | drive; + dib8000_write_word(state, 1802, reg); +} + +static u32 dib8096p_calcSyncFreq(u32 P_Kin, u32 P_Kout, + u32 insertExtSynchro, u32 syncSize) +{ + u32 quantif = 3; + u32 nom = (insertExtSynchro * P_Kin+syncSize); + u32 denom = P_Kout; + u32 syncFreq = ((nom << quantif) / denom); + + if ((syncFreq & ((1 << quantif) - 1)) != 0) + syncFreq = (syncFreq >> quantif) + 1; + else + syncFreq = (syncFreq >> quantif); + + if (syncFreq != 0) + syncFreq = syncFreq - 1; + + return syncFreq; +} + +static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin, + u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, + u32 syncWord, u32 syncSize) +{ + dprintk("Configure DibStream Tx"); + + dib8000_write_word(state, 1615, 1); + dib8000_write_word(state, 1603, P_Kin); + dib8000_write_word(state, 1605, P_Kout); + dib8000_write_word(state, 1606, insertExtSynchro); + dib8000_write_word(state, 1608, synchroMode); + dib8000_write_word(state, 1609, (syncWord >> 16) & 0xffff); + dib8000_write_word(state, 1610, syncWord & 0xffff); + dib8000_write_word(state, 1612, syncSize); + dib8000_write_word(state, 1615, 0); +} + +static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin, + u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, + u32 syncWord, u32 syncSize, u32 dataOutRate) +{ + u32 syncFreq; + + dprintk("Configure DibStream Rx synchroMode = %d", synchroMode); + + if ((P_Kin != 0) && (P_Kout != 0)) { + syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout, + insertExtSynchro, syncSize); + dib8000_write_word(state, 1542, syncFreq); + } + + dib8000_write_word(state, 1554, 1); + dib8000_write_word(state, 1536, P_Kin); + dib8000_write_word(state, 1537, P_Kout); + dib8000_write_word(state, 1539, synchroMode); + dib8000_write_word(state, 1540, (syncWord >> 16) & 0xffff); + dib8000_write_word(state, 1541, syncWord & 0xffff); + dib8000_write_word(state, 1543, syncSize); + dib8000_write_word(state, 1544, dataOutRate); + dib8000_write_word(state, 1554, 0); +} + +static void dib8096p_enMpegMux(struct dib8000_state *state, int onoff) +{ + u16 reg_1287; + + reg_1287 = dib8000_read_word(state, 1287); + + switch (onoff) { + case 1: + reg_1287 &= ~(1 << 8); + break; + case 0: + reg_1287 |= (1 << 8); + break; + } + + dib8000_write_word(state, 1287, reg_1287); +} + +static void dib8096p_configMpegMux(struct dib8000_state *state, + u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) +{ + u16 reg_1287; + + dprintk("Enable Mpeg mux"); + + dib8096p_enMpegMux(state, 0); + + /* If the input mode is MPEG do not divide the serial clock */ + if ((enSerialMode == 1) && (state->input_mode_mpeg == 1)) + enSerialClkDiv2 = 0; + + reg_1287 = ((pulseWidth & 0x1f) << 3) | + ((enSerialMode & 0x1) << 2) | (enSerialClkDiv2 & 0x1); + dib8000_write_word(state, 1287, reg_1287); + + dib8096p_enMpegMux(state, 1); +} + +static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode) +{ + u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 7); + + switch (mode) { + case MPEG_ON_DIBTX: + dprintk("SET MPEG ON DIBSTREAM TX"); + dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); + reg_1288 |= (1 << 9); break; + case DIV_ON_DIBTX: + dprintk("SET DIV_OUT ON DIBSTREAM TX"); + dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); + reg_1288 |= (1 << 8); break; + case ADC_ON_DIBTX: + dprintk("SET ADC_OUT ON DIBSTREAM TX"); + dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); + reg_1288 |= (1 << 7); break; + default: + break; + } + dib8000_write_word(state, 1288, reg_1288); +} + +static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode) +{ + u16 reg_1288 = dib8000_read_word(state, 1288) & ~(0x7 << 4); + + switch (mode) { + case DEMOUT_ON_HOSTBUS: + dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); + dib8096p_enMpegMux(state, 0); + reg_1288 |= (1 << 6); + break; + case DIBTX_ON_HOSTBUS: + dprintk("SET DIBSTREAM TX ON HOST BUS"); + dib8096p_enMpegMux(state, 0); + reg_1288 |= (1 << 5); + break; + case MPEG_ON_HOSTBUS: + dprintk("SET MPEG MUX ON HOST BUS"); + reg_1288 |= (1 << 4); + break; + default: + break; + } + dib8000_write_word(state, 1288, reg_1288); +} + +static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 reg_1287; + + switch (onoff) { + case 0: /* only use the internal way - not the diversity input */ + dprintk("%s mode OFF : by default Enable Mpeg INPUT", + __func__); + /* outputRate = 8 */ + dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); + + /* Do not divide the serial clock of MPEG MUX in + SERIAL MODE in case input mode MPEG is used */ + reg_1287 = dib8000_read_word(state, 1287); + /* enSerialClkDiv2 == 1 ? */ + if ((reg_1287 & 0x1) == 1) { + /* force enSerialClkDiv2 = 0 */ + reg_1287 &= ~0x1; + dib8000_write_word(state, 1287, reg_1287); + } + state->input_mode_mpeg = 1; + break; + case 1: /* both ways */ + case 2: /* only the diversity input */ + dprintk("%s ON : Enable diversity INPUT", __func__); + dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); + state->input_mode_mpeg = 0; + break; + } + + dib8000_set_diversity_in(state->fe[0], onoff); + return 0; +} + +static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 outreg, smo_mode, fifo_threshold; + u8 prefer_mpeg_mux_use = 1; + int ret = 0; + + dib8096p_host_bus_drive(state, 1); + + fifo_threshold = 1792; + smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); + outreg = dib8000_read_word(state, 1286) & + ~((1 << 10) | (0x7 << 6) | (1 << 1)); + + switch (mode) { + case OUTMODE_HIGH_Z: + outreg = 0; + break; + + case OUTMODE_MPEG2_SERIAL: + if (prefer_mpeg_mux_use) { + dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux"); + dib8096p_configMpegMux(state, 3, 1, 1); + dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else {/* Use Smooth block */ + dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc"); + dib8096p_setHostBusMux(state, + DEMOUT_ON_HOSTBUS); + outreg |= (2 << 6) | (0 << 1); + } + break; + + case OUTMODE_MPEG2_PAR_GATED_CLK: + if (prefer_mpeg_mux_use) { + dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dib8096p_configMpegMux(state, 2, 0, 0); + dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); + } else { /* Use Smooth block */ + dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block"); + dib8096p_setHostBusMux(state, + DEMOUT_ON_HOSTBUS); + outreg |= (0 << 6); + } + break; + + case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ + dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block"); + dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (1 << 6); + break; + + case OUTMODE_MPEG2_FIFO: + /* Using Smooth block because not supported + by new Mpeg Mux bloc */ + dprintk("dib8096P setting output mode TS_FIFO using Smooth block"); + dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); + outreg |= (5 << 6); + smo_mode |= (3 << 1); + fifo_threshold = 512; + break; + + case OUTMODE_DIVERSITY: + dprintk("dib8096P setting output mode MODE_DIVERSITY"); + dib8096p_setDibTxMux(state, DIV_ON_DIBTX); + dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); + break; + + case OUTMODE_ANALOG_ADC: + dprintk("dib8096P setting output mode MODE_ANALOG_ADC"); + dib8096p_setDibTxMux(state, ADC_ON_DIBTX); + dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); + break; + } + + if (mode != OUTMODE_HIGH_Z) + outreg |= (1<<10); + + dprintk("output_mpeg2_in_188_bytes = %d", + state->cfg.output_mpeg2_in_188_bytes); + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + + ret |= dib8000_write_word(state, 299, smo_mode); + /* synchronous fread */ + ret |= dib8000_write_word(state, 299 + 1, fifo_threshold); + ret |= dib8000_write_word(state, 1286, outreg); + + return ret; +} + +static int map_addr_to_serpar_number(struct i2c_msg *msg) +{ + if (msg->buf[0] <= 15) + msg->buf[0] -= 1; + else if (msg->buf[0] == 17) + msg->buf[0] = 15; + else if (msg->buf[0] == 16) + msg->buf[0] = 17; + else if (msg->buf[0] == 19) + msg->buf[0] = 16; + else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) + msg->buf[0] -= 3; + else if (msg->buf[0] == 28) + msg->buf[0] = 23; + else if (msg->buf[0] == 99) + msg->buf[0] = 99; + else + return -EINVAL; + return 0; +} + +static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + + while (n_overflow == 1 && i) { + n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("Tuner ITF: write busy (overflow)"); + } + dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); + dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); + + return num; +} + +static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1, n_empty = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + u16 read_word; + + while (n_overflow == 1 && i) { + n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (overflow)"); + } + dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f)); + + i = 1000; + while (n_empty == 1 && i) { + n_empty = dib8000_read_word(state, 1984)&0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (empty)"); + } + + read_word = dib8000_read_word(state, 1987); + msg[1].buf[0] = (read_word >> 8) & 0xff; + msg[1].buf[1] = (read_word) & 0xff; + + return num; +} + +static int dib8096p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + if (map_addr_to_serpar_number(&msg[0]) == 0) { + if (num == 1) /* write */ + return dib8096p_tuner_write_serpar(i2c_adap, msg, 1); + else /* read */ + return dib8096p_tuner_read_serpar(i2c_adap, msg, 2); + } + return num; +} + +static int dib8096p_rw_on_apb(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num, u16 apb_address) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u16 word; + + if (num == 1) { /* write */ + dib8000_write_word(state, apb_address, + ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); + } else { + word = dib8000_read_word(state, apb_address); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + } + return num; +} + +static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msg[], int num) +{ + struct dib8000_state *state = i2c_get_adapdata(i2c_adap); + u16 apb_address = 0, word; + int i = 0; + + switch (msg[0].buf[0]) { + case 0x12: + apb_address = 1920; + break; + case 0x14: + apb_address = 1921; + break; + case 0x24: + apb_address = 1922; + break; + case 0x1a: + apb_address = 1923; + break; + case 0x22: + apb_address = 1924; + break; + case 0x33: + apb_address = 1926; + break; + case 0x34: + apb_address = 1927; + break; + case 0x35: + apb_address = 1928; + break; + case 0x36: + apb_address = 1929; + break; + case 0x37: + apb_address = 1930; + break; + case 0x38: + apb_address = 1931; + break; + case 0x39: + apb_address = 1932; + break; + case 0x2a: + apb_address = 1935; + break; + case 0x2b: + apb_address = 1936; + break; + case 0x2c: + apb_address = 1937; + break; + case 0x2d: + apb_address = 1938; + break; + case 0x2e: + apb_address = 1939; + break; + case 0x2f: + apb_address = 1940; + break; + case 0x30: + apb_address = 1941; + break; + case 0x31: + apb_address = 1942; + break; + case 0x32: + apb_address = 1943; + break; + case 0x3e: + apb_address = 1944; + break; + case 0x3f: + apb_address = 1945; + break; + case 0x40: + apb_address = 1948; + break; + case 0x25: + apb_address = 936; + break; + case 0x26: + apb_address = 937; + break; + case 0x27: + apb_address = 938; + break; + case 0x28: + apb_address = 939; + break; + case 0x1d: + /* get sad sel request */ + i = ((dib8000_read_word(state, 921) >> 12)&0x3); + word = dib8000_read_word(state, 924+i); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + return num; + case 0x1f: + if (num == 1) { /* write */ + word = (u16) ((msg[0].buf[1] << 8) | + msg[0].buf[2]); + /* in the VGAMODE Sel are located on bit 0/1 */ + word &= 0x3; + word = (dib8000_read_word(state, 921) & + ~(3<<12)) | (word<<12); + /* Set the proper input */ + dib8000_write_word(state, 921, word); + return num; + } + } + + if (apb_address != 0) /* R/W acces via APB */ + return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address); + else /* R/W access via SERPAR */ + return dib8096p_tuner_rw_serpar(i2c_adap, msg, num); + + return 0; +} + +static u32 dib8096p_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dib8096p_tuner_xfer_algo = { + .master_xfer = dib8096p_tuner_xfer, + .functionality = dib8096p_i2c_func, +}; + +struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) +{ + struct dib8000_state *st = fe->demodulator_priv; + return &st->dib8096p_tuner_adap; +} +EXPORT_SYMBOL(dib8096p_get_i2c_tuner); + +int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + struct dib8000_state *state = fe->demodulator_priv; + u16 en_cur_state; + + dprintk("sleep dib8096p: %d", onoff); + + en_cur_state = dib8000_read_word(state, 1922); + + /* LNAs and MIX are ON and therefore it is a valid configuration */ + if (en_cur_state > 0xff) + state->tuner_enable = en_cur_state ; + + if (onoff) + en_cur_state &= 0x00ff; + else { + if (state->tuner_enable != 0) + en_cur_state = state->tuner_enable; + } + + dib8000_write_word(state, 1922, en_cur_state); + + return 0; +} +EXPORT_SYMBOL(dib8096p_tuner_sleep); + static const s32 lut_1000ln_mant[] = { 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 @@ -1051,6 +1815,26 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) } EXPORT_SYMBOL(dib8000_get_adc_power); +int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) +{ + struct dib8000_state *state = fe->demodulator_priv; + int val = 0; + + switch (IQ) { + case 1: + val = dib8000_read_word(state, 403); + break; + case 0: + val = dib8000_read_word(state, 404); + break; + } + if (val & 0x200) + val -= 1024; + + return val; +} +EXPORT_SYMBOL(dib8090p_get_dc_power); + static void dib8000_update_timf(struct dib8000_state *state) { u32 timf = state->timf = dib8000_read32(state, 435); @@ -1060,6 +1844,26 @@ static void dib8000_update_timf(struct dib8000_state *state) dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); } +u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) +{ + struct dib8000_state *state = fe->demodulator_priv; + + switch (op) { + case DEMOD_TIMF_SET: + state->timf = timf; + break; + case DEMOD_TIMF_UPDATE: + dib8000_update_timf(state); + break; + case DEMOD_TIMF_GET: + break; + } + dib8000_set_bandwidth(state->fe[0], 6000); + + return state->timf; +} +EXPORT_SYMBOL(dib8000_ctrl_timf); + static const u16 adc_target_16dB[11] = { (1 << 13) - 825 - 117, (1 << 13) - 837 - 117, @@ -1086,6 +1890,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear u16 init_prbs = 0xfff; u16 ana_gain = 0; + if (state->revision == 0x8090) + dib8000_init_sdram(state); + if (state->ber_monitored_layer != LAYER_ALL) dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); else @@ -1418,7 +2225,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); state->differential_constellation = (seg_diff_mask != 0); - dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + if (state->revision != 0x8090) + dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + else + dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff); if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) @@ -1870,7 +2680,7 @@ static int dib8000_tune(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; int ret = 0; - u16 value, mode = fft_to_mode(state); + u16 lock, value, mode = fft_to_mode(state); // we are already tuned - just resuming from suspend if (state == NULL) @@ -1924,7 +2734,11 @@ static int dib8000_tune(struct dvb_frontend *fe) } // we achieved a coff_cpil_lock - it's time to update the timf - if ((dib8000_read_word(state, 568) >> 11) & 0x1) + if (state->revision != 0x8090) + lock = dib8000_read_word(state, 568); + else + lock = dib8000_read_word(state, 570); + if ((lock >> 11) & 0x1) dib8000_update_timf(state); //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start @@ -1946,11 +2760,14 @@ static int dib8000_wakeup(struct dvb_frontend *fe) u8 index_frontend; int ret; - dib8000_set_power_mode(state, DIB8000M_POWER_ALL); + dib8000_set_power_mode(state, DIB8000_POWER_ALL); dib8000_set_adc_state(state, DIBX000_ADC_ON); if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) dprintk("could not start Slow ADC"); + if (state->revision != 0x8090) + dib8000_sad_calib(state); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); if (ret < 0) @@ -1972,8 +2789,9 @@ static int dib8000_sleep(struct dvb_frontend *fe) return ret; } - dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); - dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + if (state->revision != 0x8090) + dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); + dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); } @@ -1992,7 +2810,7 @@ int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun } EXPORT_SYMBOL(dib8000_set_tune_state); -static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib8000_get_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u16 i, val = 0; @@ -2006,7 +2824,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par if (stat&FE_HAS_SYNC) { dprintk("TMCC lock on the slave%i", index_frontend); /* synchronize the cache with the other frontends */ - state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]); for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { if (sub_index_frontend != index_frontend) { state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; @@ -2028,7 +2846,10 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; - val = dib8000_read_word(state, 570); + if (state->revision == 0x8090) + val = dib8000_read_word(state, 572); + else + val = dib8000_read_word(state, 570); fe->dtv_property_cache.inversion = (val & 0x40) >> 6; switch ((val & 0x30) >> 4) { case 1: @@ -2135,7 +2956,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par return 0; } -static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib8000_set_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; u8 nbr_pending, exit_condition, index_frontend; @@ -2158,9 +2979,14 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); - dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); + if (state->revision != 0x8090) + dib8000_set_output_mode(state->fe[index_frontend], + OUTMODE_HIGH_Z); + else + dib8096p_set_output_mode(state->fe[index_frontend], + OUTMODE_HIGH_Z); if (state->fe[index_frontend]->ops.tuner_ops.set_params) - state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep); + state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]); dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); } @@ -2215,7 +3041,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { - int i = 80000; + int i = 100; u8 found = 0; u8 tune_failed = 0; @@ -2243,6 +3069,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par default: dprintk("unhandled autosearch result"); case 1: + tune_failed |= (1 << index_frontend); dprintk("autosearch failed for the frontend%i", index_frontend); break; } @@ -2261,21 +3088,44 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("tune success on frontend%i", index_frontend_success); - dib8000_get_frontend(fe, fep); + dib8000_get_frontend(fe); } for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) ret = dib8000_tune(state->fe[index_frontend]); /* set output mode and diversity input */ - dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); - for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); - dib8000_set_diversity_in(state->fe[index_frontend-1], 1); - } + if (state->revision != 0x8090) { + dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); + for (index_frontend = 1; + (index_frontend < MAX_NUMBER_OF_FRONTENDS) && + (state->fe[index_frontend] != NULL); + index_frontend++) { + dib8000_set_output_mode(state->fe[index_frontend], + OUTMODE_DIVERSITY); + dib8000_set_diversity_in(state->fe[index_frontend-1], 1); + } - /* turn off the diversity of the last chip */ - dib8000_set_diversity_in(state->fe[index_frontend-1], 0); + /* turn off the diversity of the last chip */ + dib8000_set_diversity_in(state->fe[index_frontend-1], 0); + } else { + dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode); + if (state->cfg.enMpegOutput == 0) { + dib8096p_setDibTxMux(state, MPEG_ON_DIBTX); + dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); + } + for (index_frontend = 1; + (index_frontend < MAX_NUMBER_OF_FRONTENDS) && + (state->fe[index_frontend] != NULL); + index_frontend++) { + dib8096p_set_output_mode(state->fe[index_frontend], + OUTMODE_DIVERSITY); + dib8096p_set_diversity_in(state->fe[index_frontend-1], 1); + } + + /* turn off the diversity of the last chip */ + dib8096p_set_diversity_in(state->fe[index_frontend-1], 0); + } return ret; } @@ -2284,15 +3134,22 @@ static u16 dib8000_read_lock(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + if (state->revision == 0x8090) + return dib8000_read_word(state, 570); return dib8000_read_word(state, 568); } static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) { struct dib8000_state *state = fe->demodulator_priv; - u16 lock_slave = 0, lock = dib8000_read_word(state, 568); + u16 lock_slave = 0, lock; u8 index_frontend; + if (state->revision == 0x8090) + lock = dib8000_read_word(state, 570); + else + lock = dib8000_read_word(state, 568); + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib8000_read_lock(state->fe[index_frontend]); @@ -2330,14 +3187,26 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) static int dib8000_read_ber(struct dvb_frontend *fe, u32 * ber) { struct dib8000_state *state = fe->demodulator_priv; - *ber = (dib8000_read_word(state, 560) << 16) | dib8000_read_word(state, 561); // 13 segments + + /* 13 segments */ + if (state->revision == 0x8090) + *ber = (dib8000_read_word(state, 562) << 16) | + dib8000_read_word(state, 563); + else + *ber = (dib8000_read_word(state, 560) << 16) | + dib8000_read_word(state, 561); return 0; } static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) { struct dib8000_state *state = fe->demodulator_priv; - *unc = dib8000_read_word(state, 565); // packet error on 13 seg + + /* packet error on 13 seg */ + if (state->revision == 0x8090) + *unc = dib8000_read_word(state, 567); + else + *unc = dib8000_read_word(state, 565); return 0; } @@ -2370,14 +3239,20 @@ static u32 dib8000_get_snr(struct dvb_frontend *fe) u32 n, s, exp; u16 val; - val = dib8000_read_word(state, 542); + if (state->revision != 0x8090) + val = dib8000_read_word(state, 542); + else + val = dib8000_read_word(state, 544); n = (val >> 6) & 0xff; exp = (val & 0x3f); if ((exp & 0x20) != 0) exp -= 0x40; n <<= exp+16; - val = dib8000_read_word(state, 543); + if (state->revision != 0x8090) + val = dib8000_read_word(state, 543); + else + val = dib8000_read_word(state, 545); s = (val >> 6) & 0xff; exp = (val & 0x3f); if ((exp & 0x20) != 0) @@ -2401,7 +3276,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib8000_get_snr(state->fe[index_frontend]); - if (snr_master != 0) { + if ((snr_master >> 16) != 0) { snr_master = 10*intlog10(snr_master>>16); *snr = snr_master / ((1 << 24) / 10); } @@ -2458,7 +3333,8 @@ struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int sla EXPORT_SYMBOL(dib8000_get_slave_frontend); -int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, + u8 default_addr, u8 first_addr, u8 is_dib8096p) { int k = 0, ret = 0; u8 new_addr = 0; @@ -2488,9 +3364,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau new_addr = first_addr + (k << 1); client.addr = new_addr; - dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ - if (dib8000_identify(&client) == 0) { + if (!is_dib8096p) dib8000_i2c_write16(&client, 1287, 0x0003); /* sram lead in, rdy */ + if (dib8000_identify(&client) == 0) { + /* sram lead in, rdy */ + if (!is_dib8096p) + dib8000_i2c_write16(&client, 1287, 0x0003); client.addr = default_addr; if (dib8000_identify(&client) == 0) { dprintk("#%d: not identified", k); @@ -2549,6 +3428,7 @@ static void dib8000_release(struct dvb_frontend *fe) dvb_frontend_detach(st->fe[index_frontend]); dibx000_exit_i2c_master(&st->i2c_master); + i2c_del_adapter(&st->dib8096p_tuner_adap); kfree(st->fe[0]); kfree(st); } @@ -2581,9 +3461,9 @@ int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) EXPORT_SYMBOL(dib8000_pid_filter); static const struct dvb_frontend_ops dib8000_ops = { + .delsys = { SYS_ISDBT }, .info = { .name = "DiBcom 8000 ISDB-T", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, @@ -2651,6 +3531,15 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); + /* init 8096p tuner adapter */ + strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", + sizeof(state->dib8096p_tuner_adap.name)); + state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; + state->dib8096p_tuner_adap.algo_data = NULL; + state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; + i2c_set_adapdata(&state->dib8096p_tuner_adap, state); + i2c_add_adapter(&state->dib8096p_tuner_adap); + dib8000_reset(fe); dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index 617f9eba3a09..39591bb172c1 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -32,6 +32,7 @@ struct dib8000_config { u8 div_cfg; u8 output_mode; u8 refclksel; + u8 enMpegOutput:1; }; #define DEFAULT_DIB8000_I2C_ADDRESS 18 @@ -40,7 +41,8 @@ struct dib8000_config { extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); -extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); +extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, + u8 default_addr, u8 first_addr, u8 is_dib8096p); extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); @@ -50,6 +52,13 @@ extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_st extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); +extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe); +extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff); +extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ); +extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe, + uint8_t op, uint32_t timf); +extern int dib8000_update_pll(struct dvb_frontend *fe, + struct dibx000_bandwidth_config *pll); extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); @@ -66,7 +75,9 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe return NULL; } -static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, + int no_of_demods, u8 default_addr, u8 first_addr, + u8 is_dib8096p) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; @@ -109,11 +120,38 @@ static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); } +static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return 0; } +static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe, + uint8_t op, uint32_t timf) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} +static inline int dib8000_update_pll(struct dvb_frontend *fe, + struct dibx000_bandwidth_config *pll) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index 660f80661ed4..863ef3cfab9f 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -1136,7 +1136,7 @@ static int dib9000_fw_init(struct dib9000_state *state) return 0; } -static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch) +static void dib9000_fw_set_channel_head(struct dib9000_state *state) { u8 b[9]; u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; @@ -1157,7 +1157,7 @@ static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_ dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); } -static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +static int dib9000_fw_get_channel(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; struct dibDVBTChannel { @@ -1309,7 +1309,7 @@ error: return ret; } -static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +static int dib9000_fw_set_channel_union(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; struct dibDVBTChannel { @@ -1454,7 +1454,7 @@ static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_fron return 0; } -static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +static int dib9000_fw_tune(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; @@ -1462,7 +1462,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete switch (state->tune_state) { case CT_DEMOD_START: - dib9000_fw_set_channel_head(state, ch); + dib9000_fw_set_channel_head(state); /* write the channel context - a channel is initialized to 0, so it is OK */ dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); @@ -1471,7 +1471,7 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete if (search) dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); else { - dib9000_fw_set_channel_union(fe, ch); + dib9000_fw_set_channel_union(fe); dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); } state->tune_state = CT_DEMOD_STEP_1; @@ -1867,7 +1867,7 @@ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron return 0; } -static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib9000_get_frontend(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend, sub_index_frontend; @@ -1883,7 +1883,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("TPS lock on the slave%i", index_frontend); /* synchronize the cache with the other frontends */ - state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend]); for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { if (sub_index_frontend != index_frontend) { @@ -1911,7 +1911,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } /* get the channel from master chip */ - ret = dib9000_fw_get_channel(fe, fep); + ret = dib9000_fw_get_channel(fe); if (ret != 0) goto return_value; @@ -1958,7 +1958,7 @@ static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_fronte return 0; } -static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int dib9000_set_frontend(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; int sleep_time, sleep_time_slave; @@ -1983,8 +1983,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par fe->dtv_property_cache.delivery_system = SYS_DVBT; /* set the master status */ - if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO || + state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO || + state->fe[0]->dtv_property_cache.modulation == QAM_AUTO || + state->fe[0]->dtv_property_cache.code_rate_HP == FEC_AUTO) { /* no channel specified, autosearch the channel */ state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; } else @@ -2008,9 +2010,9 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ index_frontend_success = 0; do { - sleep_time = dib9000_fw_tune(state->fe[0], NULL); + sleep_time = dib9000_fw_tune(state->fe[0]); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); if (sleep_time == FE_CALLBACK_TIME_NEVER) sleep_time = sleep_time_slave; else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) @@ -2052,7 +2054,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* synchronize all the channel cache */ state->get_frontend_internal = 1; - dib9000_get_frontend(state->fe[0], fep); + dib9000_get_frontend(state->fe[0]); state->get_frontend_internal = 0; /* retune the other frontends with the found channel */ @@ -2068,7 +2070,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par sleep_time = FE_CALLBACK_TIME_NEVER; for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (index_frontend != index_frontend_success) { - sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend]); if (sleep_time == FE_CALLBACK_TIME_NEVER) sleep_time = sleep_time_slave; else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) @@ -2495,9 +2497,9 @@ error: EXPORT_SYMBOL(dib9000_attach); static struct dvb_frontend_ops dib9000_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 9000", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5e011474be43..5f484881d7b1 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -146,14 +146,8 @@ enum dibx000_adc_states { DIBX000_VBG_DISABLE, }; -#define BANDWIDTH_TO_KHZ(v) ((v) == BANDWIDTH_8_MHZ ? 8000 : \ - (v) == BANDWIDTH_7_MHZ ? 7000 : \ - (v) == BANDWIDTH_6_MHZ ? 6000 : 8000) - -#define BANDWIDTH_TO_INDEX(v) ( \ - (v) == 8000 ? BANDWIDTH_8_MHZ : \ - (v) == 7000 ? BANDWIDTH_7_MHZ : \ - (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) +#define BANDWIDTH_TO_KHZ(v) ((v) / 1000) +#define BANDWIDTH_TO_HZ(v) ((v) * 1000) /* Chip output mode. */ #define OUTMODE_HIGH_Z 0 @@ -276,4 +270,11 @@ struct dibSubbandSelection { #define DEMOD_TIMF_GET 0x01 #define DEMOD_TIMF_UPDATE 0x02 +#define MPEG_ON_DIBTX 1 +#define DIV_ON_DIBTX 2 +#define ADC_ON_DIBTX 3 +#define DEMOUT_ON_HOSTBUS 4 +#define DIBTX_ON_HOSTBUS 5 +#define MPEG_ON_HOSTBUS 6 + #endif diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h index 7113535844f2..34398738f9bc 100644 --- a/drivers/media/dvb/frontends/drxd.h +++ b/drivers/media/dvb/frontends/drxd.h @@ -48,8 +48,6 @@ struct drxd_config { u8 disable_i2c_gate_ctrl; u32 IF; - int (*pll_set) (void *priv, void *priv_params, - u8 pll_addr, u8 demoda_addr, s32 *off); s16(*osc_deviation) (void *priv, s16 dev, int flag); }; diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c index 88e46f4cdbb2..7bf39cda83c5 100644 --- a/drivers/media/dvb/frontends/drxd_hard.c +++ b/drivers/media/dvb/frontends/drxd_hard.c @@ -120,7 +120,7 @@ enum EIFFilter { struct drxd_state { struct dvb_frontend frontend; struct dvb_frontend_ops ops; - struct dvb_frontend_parameters param; + struct dtv_frontend_properties props; const struct firmware *fw; struct device *dev; @@ -914,14 +914,13 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) return -EIO; } - state->microcode = kmalloc(fw->size, GFP_KERNEL); + state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL); if (state->microcode == NULL) { release_firmware(fw); printk(KERN_ERR "drxd: firmware load failure: no memory\n"); return -ENOMEM; } - memcpy(state->microcode, fw->data, fw->size); state->microcode_length = fw->size; release_firmware(fw); return 0; @@ -1622,14 +1621,14 @@ static int CorrectSysClockDeviation(struct drxd_state *state) break; } - switch (state->param.u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: + switch (state->props.bandwidth_hz) { + case 8000000: bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ; break; - case BANDWIDTH_7_MHZ: + case 7000000: bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ; break; - case BANDWIDTH_6_MHZ: + case 6000000: bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ; break; default: @@ -1804,7 +1803,7 @@ static int StartDiversity(struct drxd_state *state) status = WriteTable(state, state->m_StartDiversityEnd); if (status < 0) break; - if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) { + if (state->props.bandwidth_hz == 8000000) { status = WriteTable(state, state->m_DiversityDelay8MHZ); if (status < 0) break; @@ -1906,7 +1905,7 @@ static int SetCfgNoiseCalibration(struct drxd_state *state, static int DRX_Start(struct drxd_state *state, s32 off) { - struct dvb_ofdm_parameters *p = &state->param.u.ofdm; + struct dtv_frontend_properties *p = &state->props; int status; u16 transmissionParams = 0; @@ -1971,7 +1970,7 @@ static int DRX_Start(struct drxd_state *state, s32 off) if (status < 0) break; - mirrorFreqSpect = (state->param.inversion == INVERSION_ON); + mirrorFreqSpect = (state->props.inversion == INVERSION_ON); switch (p->transmission_mode) { default: /* Not set, detect it automatically */ @@ -2021,7 +2020,7 @@ static int DRX_Start(struct drxd_state *state, s32 off) break; } - switch (p->hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_1: transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1; if (state->type_A) { @@ -2147,7 +2146,7 @@ static int DRX_Start(struct drxd_state *state, s32 off) if (status < 0) break; - switch (p->constellation) { + switch (p->modulation) { default: operationMode |= SC_RA_RAM_OP_AUTO_CONST__M; /* fall through , try first guess @@ -2331,9 +2330,11 @@ static int DRX_Start(struct drxd_state *state, s32 off) by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC functions */ - switch (p->bandwidth) { - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: + switch (p->bandwidth_hz) { + case 0: + p->bandwidth_hz = 8000000; + /* fall through */ + case 8000000: /* (64/7)*(8/8)*1000000 */ bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ; @@ -2341,14 +2342,14 @@ static int DRX_Start(struct drxd_state *state, s32 off) status = Write16(state, FE_AG_REG_IND_DEL__A, 50, 0x0000); break; - case BANDWIDTH_7_MHZ: + case 7000000: /* (64/7)*(7/8)*1000000 */ bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ; bandwidthParam = 0x4807; /*binary:0100 1000 0000 0111 */ status = Write16(state, FE_AG_REG_IND_DEL__A, 59, 0x0000); break; - case BANDWIDTH_6_MHZ: + case 6000000: /* (64/7)*(6/8)*1000000 */ bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ; bandwidthParam = 0x0F07; /*binary: 0000 1111 0000 0111 */ @@ -2887,41 +2888,26 @@ static int drxd_sleep(struct dvb_frontend *fe) return 0; } -static int drxd_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - return 0; -} - static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { return drxd_config_i2c(fe, enable); } -static int drxd_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int drxd_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct drxd_state *state = fe->demodulator_priv; s32 off = 0; - state->param = *param; + state->props = *p; DRX_Stop(state); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - /* FIXME: move PLL drivers */ - if (state->config.pll_set && - state->config.pll_set(state->priv, param, - state->config.pll_address, - state->config.demoda_address, &off) < 0) { - printk(KERN_ERR "Error in pll_set\n"); - return -1; - } - msleep(200); return DRX_Start(state, off); @@ -2935,10 +2921,9 @@ static void drxd_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops drxd_ops = { - + .delsys = { SYS_DVBT}, .info = { .name = "Micronas DRXD DVB-T", - .type = FE_OFDM, .frequency_min = 47125000, .frequency_max = 855250000, .frequency_stepsize = 166667, @@ -2958,7 +2943,6 @@ static struct dvb_frontend_ops drxd_ops = { .i2c_gate_ctrl = drxd_i2c_gate_ctrl, .set_frontend = drxd_set_frontend, - .get_frontend = drxd_get_frontend, .get_tune_settings = drxd_get_tune_settings, .read_status = drxd_read_status, diff --git a/drivers/media/dvb/frontends/drxk.h b/drivers/media/dvb/frontends/drxk.h index 58baf419560c..020981844a86 100644 --- a/drivers/media/dvb/frontends/drxk.h +++ b/drivers/media/dvb/frontends/drxk.h @@ -8,6 +8,8 @@ * struct drxk_config - Configure the initial parameters for DRX-K * * adr: I2C Address of the DRX-K + * parallel_ts: true means that the device uses parallel TS, + * Serial otherwise. * single_master: Device is on the single master mode * no_i2c_bridge: Don't switch the I2C bridge to talk with tuner * antenna_gpio: GPIO bit used to control the antenna @@ -22,22 +24,23 @@ struct drxk_config { u8 adr; bool single_master; bool no_i2c_bridge; + bool parallel_ts; bool antenna_dvbt; u16 antenna_gpio; + int chunk_size; + const char *microcode_name; }; #if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \ && defined(MODULE)) extern struct dvb_frontend *drxk_attach(const struct drxk_config *config, - struct i2c_adapter *i2c, - struct dvb_frontend **fe_t); + struct i2c_adapter *i2c); #else static inline struct dvb_frontend *drxk_attach(const struct drxk_config *config, - struct i2c_adapter *i2c, - struct dvb_frontend **fe_t) + struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c index f6431ef827dc..6980ed7b8786 100644 --- a/drivers/media/dvb/frontends/drxk_hard.c +++ b/drivers/media/dvb/frontends/drxk_hard.c @@ -368,10 +368,10 @@ static int i2c_read(struct i2c_adapter *adap, } if (debug > 2) { int i; - dprintk(2, ": read from "); + dprintk(2, ": read from"); for (i = 0; i < len; i++) printk(KERN_CONT " %02x", msg[i]); - printk(KERN_CONT "Value = "); + printk(KERN_CONT ", value = "); for (i = 0; i < alen; i++) printk(KERN_CONT " %02x", answ[i]); printk(KERN_CONT "\n"); @@ -660,7 +660,6 @@ static int init_state(struct drxk_state *state) /* io_pad_cfg_mode output mode is drive always */ /* io_pad_cfg_drive is set to power 2 (23 mA) */ u32 ulGPIOCfg = 0x0113; - u32 ulSerialMode = 1; u32 ulInvertTSClock = 0; u32 ulTSDataStrength = DRXK_MPEG_SERIAL_OUTPUT_PIN_DRIVE_STRENGTH; u32 ulTSClockkStrength = DRXK_MPEG_OUTPUT_CLK_DRIVE_STRENGTH; @@ -681,7 +680,8 @@ static int init_state(struct drxk_state *state) state->m_hasOOB = false; state->m_hasAudio = false; - state->m_ChunkSize = 124; + if (!state->m_ChunkSize) + state->m_ChunkSize = 124; state->m_oscClockFreq = 0; state->m_smartAntInverted = false; @@ -810,8 +810,6 @@ static int init_state(struct drxk_state *state) /* MPEG output configuration */ state->m_enableMPEGOutput = true; /* If TRUE; enable MPEG ouput */ state->m_insertRSByte = false; /* If TRUE; insert RS byte */ - state->m_enableParallel = true; /* If TRUE; - parallel out otherwise serial */ state->m_invertDATA = false; /* If TRUE; invert DATA signals */ state->m_invertERR = false; /* If TRUE; invert ERR signal */ state->m_invertSTR = false; /* If TRUE; invert STR signals */ @@ -856,8 +854,6 @@ static int init_state(struct drxk_state *state) state->m_bPowerDown = false; state->m_currentPowerMode = DRX_POWER_DOWN; - state->m_enableParallel = (ulSerialMode == 0); - state->m_rfmirror = (ulRfMirror == 0); state->m_IfAgcPol = false; return 0; @@ -946,6 +942,9 @@ static int GetDeviceCapabilities(struct drxk_state *state) status = read32(state, SIO_TOP_JTAGID_LO__A, &sioTopJtagidLo); if (status < 0) goto error; + +printk(KERN_ERR "drxk: status = 0x%08x\n", sioTopJtagidLo); + /* driver 0.9.0 */ switch ((sioTopJtagidLo >> 29) & 0xF) { case 0: @@ -963,7 +962,8 @@ static int GetDeviceCapabilities(struct drxk_state *state) default: state->m_deviceSpin = DRXK_SPIN_UNKNOWN; status = -EINVAL; - printk(KERN_ERR "drxk: Spin unknown\n"); + printk(KERN_ERR "drxk: Spin %d unknown\n", + (sioTopJtagidLo >> 29) & 0xF); goto error2; } switch ((sioTopJtagidLo >> 12) & 0xFF) { @@ -1190,7 +1190,9 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable) u16 sioPdrMclkCfg = 0; u16 sioPdrMdxCfg = 0; - dprintk(1, "\n"); + dprintk(1, ": mpeg %s, %s mode\n", + mpegEnable ? "enable" : "disable", + state->m_enableParallel ? "parallel" : "serial"); /* stop lock indicator process */ status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); @@ -1846,6 +1848,7 @@ static int SetOperationMode(struct drxk_state *state, */ switch (oMode) { case OM_DVBT: + dprintk(1, ": DVB-T\n"); state->m_OperationMode = oMode; status = SetDVBTStandard(state, oMode); if (status < 0) @@ -1853,6 +1856,8 @@ static int SetOperationMode(struct drxk_state *state, break; case OM_QAM_ITU_A: /* fallthrough */ case OM_QAM_ITU_C: + dprintk(1, ": DVB-C Annex %c\n", + (state->m_OperationMode == OM_QAM_ITU_A) ? 'A' : 'C'); state->m_OperationMode = oMode; status = SetQAMStandard(state, oMode); if (status < 0) @@ -1881,7 +1886,7 @@ static int Start(struct drxk_state *state, s32 offsetFreq, state->m_DrxkState != DRXK_DTV_STARTED) goto error; - state->m_bMirrorFreqSpect = (state->param.inversion == INVERSION_ON); + state->m_bMirrorFreqSpect = (state->props.inversion == INVERSION_ON); if (IntermediateFrequency < 0) { state->m_bMirrorFreqSpect = !state->m_bMirrorFreqSpect; @@ -2503,7 +2508,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state, u16 qamSlErrPower = 0; /* accum. error between raw and sliced symbols */ u32 qamSlSigPower = 0; /* used for MER, depends of - QAM constellation */ + QAM modulation */ u32 qamSlMer = 0; /* QAM MER */ dprintk(1, "\n"); @@ -2517,7 +2522,7 @@ static int GetQAMSignalToNoise(struct drxk_state *state, return -EINVAL; } - switch (state->param.u.qam.modulation) { + switch (state->props.modulation) { case QAM_16: qamSlSigPower = DRXK_QAM_SL_SIG_POWER_QAM16 << 2; break; @@ -2748,7 +2753,7 @@ static int GetDVBCQuality(struct drxk_state *state, s32 *pQuality) if (status < 0) break; - switch (state->param.u.qam.modulation) { + switch (state->props.modulation) { case QAM_16: SignalToNoiseRel = SignalToNoise - 200; break; @@ -3813,7 +3818,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, /*== Write channel settings to device =====================================*/ /* mode */ - switch (state->param.u.ofdm.transmission_mode) { + switch (state->props.transmission_mode) { case TRANSMISSION_MODE_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; @@ -3827,7 +3832,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, } /* guard */ - switch (state->param.u.ofdm.guard_interval) { + switch (state->props.guard_interval) { default: case GUARD_INTERVAL_AUTO: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; @@ -3847,7 +3852,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, } /* hierarchy */ - switch (state->param.u.ofdm.hierarchy_information) { + switch (state->props.hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: default: @@ -3867,8 +3872,8 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, } - /* constellation */ - switch (state->param.u.ofdm.constellation) { + /* modulation */ + switch (state->props.modulation) { case QAM_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; @@ -3911,7 +3916,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, #endif /* coderate */ - switch (state->param.u.ofdm.code_rate_HP) { + switch (state->props.code_rate_HP) { case FEC_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; @@ -3940,9 +3945,11 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, /* Also set parameters for EC_OC fix, note EC_OC_REG_TMD_HIL_MAR is changed by SC for fix for some 8K,1/8 guard but is restored by InitEC and ResetEC functions */ - switch (state->param.u.ofdm.bandwidth) { - case BANDWIDTH_AUTO: - case BANDWIDTH_8_MHZ: + switch (state->props.bandwidth_hz) { + case 0: + state->props.bandwidth_hz = 8000000; + /* fall though */ + case 8000000: bandwidth = DRXK_BANDWIDTH_8MHZ_IN_HZ; status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3052); if (status < 0) @@ -3961,7 +3968,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; break; - case BANDWIDTH_7_MHZ: + case 7000000: bandwidth = DRXK_BANDWIDTH_7MHZ_IN_HZ; status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 3491); if (status < 0) @@ -3980,7 +3987,7 @@ static int SetDVBT(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; break; - case BANDWIDTH_6_MHZ: + case 6000000: bandwidth = DRXK_BANDWIDTH_6MHZ_IN_HZ; status = write16(state, OFDM_SC_RA_RAM_SRMM_FIX_FACT_8K__A, 4073); if (status < 0) @@ -4187,7 +4194,7 @@ error: /** * \brief Setup of the QAM Measurement intervals for signal quality * \param demod instance of demod. -* \param constellation current constellation. +* \param modulation current modulation. * \return DRXStatus_t. * * NOTE: @@ -4196,7 +4203,7 @@ error: * */ static int SetQAMMeasurement(struct drxk_state *state, - enum EDrxkConstellation constellation, + enum EDrxkConstellation modulation, u32 symbolRate) { u32 fecBitsDesired = 0; /* BER accounting period */ @@ -4210,11 +4217,11 @@ static int SetQAMMeasurement(struct drxk_state *state, fecRsPrescale = 1; /* fecBitsDesired = symbolRate [kHz] * FrameLenght [ms] * - (constellation + 1) * + (modulation + 1) * SyncLoss (== 1) * ViterbiLoss (==1) */ - switch (constellation) { + switch (modulation) { case DRX_CONSTELLATION_QAM16: fecBitsDesired = 4 * symbolRate; break; @@ -5281,12 +5288,12 @@ static int QAMSetSymbolrate(struct drxk_state *state) /* Select & calculate correct IQM rate */ adcFrequency = (state->m_sysClockFreq * 1000) / 3; ratesel = 0; - /* printk(KERN_DEBUG "drxk: SR %d\n", state->param.u.qam.symbol_rate); */ - if (state->param.u.qam.symbol_rate <= 1188750) + /* printk(KERN_DEBUG "drxk: SR %d\n", state->props.symbol_rate); */ + if (state->props.symbol_rate <= 1188750) ratesel = 3; - else if (state->param.u.qam.symbol_rate <= 2377500) + else if (state->props.symbol_rate <= 2377500) ratesel = 2; - else if (state->param.u.qam.symbol_rate <= 4755000) + else if (state->props.symbol_rate <= 4755000) ratesel = 1; status = write16(state, IQM_FD_RATESEL__A, ratesel); if (status < 0) @@ -5295,7 +5302,7 @@ static int QAMSetSymbolrate(struct drxk_state *state) /* IqmRcRate = ((Fadc / (symbolrate * (4<<ratesel))) - 1) * (1<<23) */ - symbFreq = state->param.u.qam.symbol_rate * (1 << ratesel); + symbFreq = state->props.symbol_rate * (1 << ratesel); if (symbFreq == 0) { /* Divide by zero */ status = -EINVAL; @@ -5311,7 +5318,7 @@ static int QAMSetSymbolrate(struct drxk_state *state) /* LcSymbFreq = round (.125 * symbolrate / adcFreq * (1<<15)) */ - symbFreq = state->param.u.qam.symbol_rate; + symbFreq = state->props.symbol_rate; if (adcFrequency == 0) { /* Divide by zero */ status = -EINVAL; @@ -5412,7 +5419,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, goto error; /* Set params */ - switch (state->param.u.qam.modulation) { + switch (state->props.modulation) { case QAM_256: state->m_Constellation = DRX_CONSTELLATION_QAM256; break; @@ -5435,7 +5442,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, } if (status < 0) goto error; - setParamParameters[0] = state->m_Constellation; /* constellation */ + setParamParameters[0] = state->m_Constellation; /* modulation */ setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ if (state->m_OperationMode == OM_QAM_ITU_C) setParamParameters[2] = QAM_TOP_ANNEX_C; @@ -5457,7 +5464,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; - setParamParameters[0] = state->m_Constellation; /* constellation */ + setParamParameters[0] = state->m_Constellation; /* modulation */ setParamParameters[1] = DRXK_QAM_I12_J17; /* interleave mode */ status = scu_command(state, SCU_RAM_COMMAND_STANDARD_QAM | SCU_RAM_COMMAND_CMD_DEMOD_SET_PARAM, 2, setParamParameters, 1, &cmdResult); } @@ -5466,7 +5473,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, /* * STEP 3: enable the system in a mode where the ADC provides valid - * signal setup constellation independent registers + * signal setup modulation independent registers */ #if 0 status = SetFrequency(channel, tunerFreqOffset)); @@ -5478,7 +5485,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, goto error; /* Setup BER measurement */ - status = SetQAMMeasurement(state, state->m_Constellation, state->param.u. qam.symbol_rate); + status = SetQAMMeasurement(state, state->m_Constellation, state->props.symbol_rate); if (status < 0) goto error; @@ -5560,8 +5567,8 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, if (status < 0) goto error; - /* STEP 4: constellation specific setup */ - switch (state->param.u.qam.modulation) { + /* STEP 4: modulation specific setup */ + switch (state->props.modulation) { case QAM_16: status = SetQAM16(state); break; @@ -5591,7 +5598,7 @@ static int SetQAM(struct drxk_state *state, u16 IntermediateFreqkHz, goto error; /* Re-configure MPEG output, requires knowledge of channel bitrate */ - /* extAttr->currentChannel.constellation = channel->constellation; */ + /* extAttr->currentChannel.modulation = channel->modulation; */ /* extAttr->currentChannel.symbolrate = channel->symbolrate; */ status = MPEGTSDtoSetup(state, state->m_OperationMode); if (status < 0) @@ -6167,7 +6174,7 @@ error: return status; } -static void drxk_c_release(struct dvb_frontend *fe) +static void drxk_release(struct dvb_frontend *fe) { struct drxk_state *state = fe->demodulator_priv; @@ -6175,24 +6182,12 @@ static void drxk_c_release(struct dvb_frontend *fe) kfree(state); } -static int drxk_c_init(struct dvb_frontend *fe) -{ - struct drxk_state *state = fe->demodulator_priv; - - dprintk(1, "\n"); - if (mutex_trylock(&state->ctlock) == 0) - return -EBUSY; - SetOperationMode(state, OM_QAM_ITU_A); - return 0; -} - -static int drxk_c_sleep(struct dvb_frontend *fe) +static int drxk_sleep(struct dvb_frontend *fe) { struct drxk_state *state = fe->demodulator_priv; dprintk(1, "\n"); ShutDown(state); - mutex_unlock(&state->ctlock); return 0; } @@ -6204,9 +6199,10 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) return ConfigureI2CBridge(state, enable ? true : false); } -static int drxk_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int drxk_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 delsys = p->delivery_system, old_delsys; struct drxk_state *state = fe->demodulator_priv; u32 IF; @@ -6218,14 +6214,39 @@ static int drxk_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - state->param = *p; + + old_delsys = state->props.delivery_system; + state->props = *p; + + if (old_delsys != delsys) { + ShutDown(state); + switch (delsys) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (!state->m_hasDVBC) + return -EINVAL; + state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? true : false; + if (state->m_itut_annex_c) + SetOperationMode(state, OM_QAM_ITU_C); + else + SetOperationMode(state, OM_QAM_ITU_A); + break; + case SYS_DVBT: + if (!state->m_hasDVBT) + return -EINVAL; + SetOperationMode(state, OM_DVBT); + break; + default: + return -EINVAL; + } + } + fe->ops.tuner_ops.get_if_frequency(fe, &IF); Start(state, 0, IF); @@ -6234,13 +6255,6 @@ static int drxk_set_parameters(struct dvb_frontend *fe, return 0; } -static int drxk_c_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - dprintk(1, "\n"); - return 0; -} - static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct drxk_state *state = fe->demodulator_priv; @@ -6300,102 +6314,54 @@ static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int drxk_c_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings +static int drxk_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *sets) { - dprintk(1, "\n"); - sets->min_delay_ms = 3000; - sets->max_drift = 0; - sets->step_size = 0; - return 0; -} - -static void drxk_t_release(struct dvb_frontend *fe) -{ - /* - * There's nothing to release here, as the state struct - * is already freed by drxk_c_release. - */ -} - -static int drxk_t_init(struct dvb_frontend *fe) -{ - struct drxk_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; dprintk(1, "\n"); - if (mutex_trylock(&state->ctlock) == 0) - return -EBUSY; - SetOperationMode(state, OM_DVBT); - return 0; -} - -static int drxk_t_sleep(struct dvb_frontend *fe) -{ - struct drxk_state *state = fe->demodulator_priv; - - dprintk(1, "\n"); - mutex_unlock(&state->ctlock); - return 0; -} - -static int drxk_t_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - dprintk(1, "\n"); - - return 0; + switch (p->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + sets->min_delay_ms = 3000; + sets->max_drift = 0; + sets->step_size = 0; + return 0; + default: + /* + * For DVB-T, let it use the default DVB core way, that is: + * fepriv->step_size = fe->ops.info.frequency_stepsize * 2 + */ + return -EINVAL; + } } -static struct dvb_frontend_ops drxk_c_ops = { +static struct dvb_frontend_ops drxk_ops = { + /* .delsys will be filled dynamically */ .info = { - .name = "DRXK DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 47000000, - .frequency_max = 862000000, - .symbol_rate_min = 870000, - .symbol_rate_max = 11700000, - .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO}, - .release = drxk_c_release, - .init = drxk_c_init, - .sleep = drxk_c_sleep, + .name = "DRXK", + .frequency_min = 47000000, + .frequency_max = 865000000, + /* For DVB-C */ + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + /* For DVB-T */ + .frequency_stepsize = 166667, + + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO | + 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_MUTE_TS | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO + }, + + .release = drxk_release, + .sleep = drxk_sleep, .i2c_gate_ctrl = drxk_gate_ctrl, .set_frontend = drxk_set_parameters, - .get_frontend = drxk_c_get_frontend, - .get_tune_settings = drxk_c_get_tune_settings, - - .read_status = drxk_read_status, - .read_ber = drxk_read_ber, - .read_signal_strength = drxk_read_signal_strength, - .read_snr = drxk_read_snr, - .read_ucblocks = drxk_read_ucblocks, -}; - -static struct dvb_frontend_ops drxk_t_ops = { - .info = { - .name = "DRXK DVB-T", - .type = FE_OFDM, - .frequency_min = 47125000, - .frequency_max = 865000000, - .frequency_stepsize = 166667, - .frequency_tolerance = 0, - .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_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS}, - .release = drxk_t_release, - .init = drxk_t_init, - .sleep = drxk_t_sleep, - .i2c_gate_ctrl = drxk_gate_ctrl, - - .set_frontend = drxk_set_parameters, - .get_frontend = drxk_t_get_frontend, + .get_tune_settings = drxk_get_tune_settings, .read_status = drxk_read_status, .read_ber = drxk_read_ber, @@ -6405,9 +6371,10 @@ static struct dvb_frontend_ops drxk_t_ops = { }; struct dvb_frontend *drxk_attach(const struct drxk_config *config, - struct i2c_adapter *i2c, - struct dvb_frontend **fe_t) + struct i2c_adapter *i2c) { + int n; + struct drxk_state *state = NULL; u8 adr = config->adr; @@ -6423,6 +6390,12 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->no_i2c_bridge = config->no_i2c_bridge; state->antenna_gpio = config->antenna_gpio; state->antenna_dvbt = config->antenna_dvbt; + state->m_ChunkSize = config->chunk_size; + + if (config->parallel_ts) + state->m_enableParallel = true; + else + state->m_enableParallel = false; /* NOTE: as more UIO bits will be used, add them to the mask */ state->UIO_mask = config->antenna_gpio; @@ -6434,21 +6407,30 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->m_GPIO &= ~state->antenna_gpio; mutex_init(&state->mutex); - mutex_init(&state->ctlock); - memcpy(&state->c_frontend.ops, &drxk_c_ops, - sizeof(struct dvb_frontend_ops)); - memcpy(&state->t_frontend.ops, &drxk_t_ops, - sizeof(struct dvb_frontend_ops)); - state->c_frontend.demodulator_priv = state; - state->t_frontend.demodulator_priv = state; + memcpy(&state->frontend.ops, &drxk_ops, sizeof(drxk_ops)); + state->frontend.demodulator_priv = state; init_state(state); if (init_drxk(state) < 0) goto error; - *fe_t = &state->t_frontend; - return &state->c_frontend; + /* Initialize the supported delivery systems */ + n = 0; + if (state->m_hasDVBC) { + state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_A; + state->frontend.ops.delsys[n++] = SYS_DVBC_ANNEX_C; + strlcat(state->frontend.ops.info.name, " DVB-C", + sizeof(state->frontend.ops.info.name)); + } + if (state->m_hasDVBT) { + state->frontend.ops.delsys[n++] = SYS_DVBT; + strlcat(state->frontend.ops.info.name, " DVB-T", + sizeof(state->frontend.ops.info.name)); + } + + printk(KERN_INFO "drxk: frontend initialized.\n"); + return &state->frontend; error: printk(KERN_ERR "drxk: not found\n"); diff --git a/drivers/media/dvb/frontends/drxk_hard.h b/drivers/media/dvb/frontends/drxk_hard.h index a05c32eecdcc..3a58b73eb9b9 100644 --- a/drivers/media/dvb/frontends/drxk_hard.h +++ b/drivers/media/dvb/frontends/drxk_hard.h @@ -195,9 +195,8 @@ struct DRXKOfdmScCmd_t { }; struct drxk_state { - struct dvb_frontend c_frontend; - struct dvb_frontend t_frontend; - struct dvb_frontend_parameters param; + struct dvb_frontend frontend; + struct dtv_frontend_properties props; struct device *dev; struct i2c_adapter *i2c; @@ -205,7 +204,6 @@ struct drxk_state { void *priv; struct mutex mutex; - struct mutex ctlock; u32 m_Instance; /**< Channel 1,2,3 or 4 */ @@ -263,6 +261,8 @@ struct drxk_state { u8 m_TSDataStrength; u8 m_TSClockkStrength; + bool m_itut_annex_c; /* If true, uses ITU-T DVB-C Annex C, instead of Annex A */ + enum DRXMPEGStrWidth_t m_widthSTR; /**< MPEG start width */ u32 m_mpegTsStaticBitrate; /**< Maximum bitrate in b/s in case static clockrate is selected */ diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 90bf573308b0..938777065de6 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -934,20 +934,6 @@ error2: } EXPORT_SYMBOL(ds3000_attach); -static int ds3000_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int ds3000_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - static int ds3000_set_carrier_offset(struct dvb_frontend *fe, s32 carrier_offset_khz) { @@ -967,8 +953,7 @@ static int ds3000_set_carrier_offset(struct dvb_frontend *fe, return 0; } -static int ds3000_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int ds3000_set_frontend(struct dvb_frontend *fe) { struct ds3000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -994,15 +979,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, div4 = 0; /* calculate and set freq divider */ - if (p->frequency < 1146000) { + if (c->frequency < 1146000) { ds3000_tuner_writereg(state, 0x10, 0x11); div4 = 1; - ndiv = ((p->frequency * (6 + 8) * 4) + + ndiv = ((c->frequency * (6 + 8) * 4) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; } else { ds3000_tuner_writereg(state, 0x10, 0x01); - ndiv = ((p->frequency * (6 + 8) * 2) + + ndiv = ((c->frequency * (6 + 8) * 2) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; } @@ -1101,7 +1086,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, msleep(60); offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ - / (6 + 8) / (div4 + 1) / 2 - p->frequency; + / (6 + 8) / (div4 + 1) / 2 - c->frequency; /* ds3000 global reset */ ds3000_writereg(state, 0x07, 0x80); @@ -1220,13 +1205,13 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, } static int ds3000_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { - if (p) { - int ret = ds3000_set_frontend(fe, p); + if (re_tune) { + int ret = ds3000_set_frontend(fe); if (ret) return ret; } @@ -1279,10 +1264,9 @@ static int ds3000_sleep(struct dvb_frontend *fe) } static struct dvb_frontend_ops ds3000_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2}, .info = { .name = "Montage Technology DS3000/TS2020", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1011, /* kHz for QPSK frontends */ @@ -1312,8 +1296,6 @@ static struct dvb_frontend_ops ds3000_ops = { .diseqc_send_burst = ds3000_diseqc_send_burst, .get_frontend_algo = ds3000_get_algo, - .set_property = ds3000_set_property, - .get_property = ds3000_get_property, .set_frontend = ds3000_set_frontend, .tune = ds3000_tune, }; diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 62a65efdf8d6..1ab34838221c 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -61,8 +61,7 @@ struct dvb_pll_desc { u32 min; u32 max; u32 iffreq; - void (*set)(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params); + void (*set)(struct dvb_frontend *fe, u8 *buf); u8 *initdata; u8 *initdata2; u8 *sleepdata; @@ -93,10 +92,10 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = { }, }; -static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf) { - if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 7000000) buf[3] |= 0x10; } @@ -186,10 +185,10 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = { /* Philips TDA6650/TDA6651 * used in Panasonic ENV77H11D5 */ -static void tda665x_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void tda665x_bw(struct dvb_frontend *fe, u8 *buf) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 8000000) buf[3] |= 0x08; } @@ -220,10 +219,10 @@ static struct dvb_pll_desc dvb_pll_tda665x = { /* Infineon TUA6034 * used in LG TDTP E102P */ -static void tua6034_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void tua6034_bw(struct dvb_frontend *fe, u8 *buf) { - if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 7000000) buf[3] |= 0x08; } @@ -244,10 +243,10 @@ static struct dvb_pll_desc dvb_pll_tua6034 = { /* ALPS TDED4 * used in Nebula-Cards and USB boxes */ -static void tded4_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void tded4_bw(struct dvb_frontend *fe, u8 *buf) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + u32 bw = fe->dtv_property_cache.bandwidth_hz; + if (bw == 8000000) buf[3] |= 0x04; } @@ -319,11 +318,11 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { }, }; -static void opera1_bw(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void opera1_bw(struct dvb_frontend *fe, u8 *buf) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_pll_priv *priv = fe->tuner_priv; - u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + u32 b_w = (c->symbol_rate * 27) / 32000; struct i2c_msg msg = { .addr = priv->pll_i2c_address, .flags = 0, @@ -392,8 +391,7 @@ static struct dvb_pll_desc dvb_pll_opera1 = { } }; -static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) +static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf) { struct dvb_pll_priv *priv = fe->tuner_priv; struct i2c_msg msg = { @@ -537,30 +535,29 @@ static struct dvb_pll_desc *pll_list[] = { /* code */ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, - const struct dvb_frontend_parameters *params) + const u32 frequency) { struct dvb_pll_priv *priv = fe->tuner_priv; struct dvb_pll_desc *desc = priv->pll_desc; u32 div; int i; - if (params->frequency != 0 && (params->frequency < desc->min || - params->frequency > desc->max)) + if (frequency && (frequency < desc->min || frequency > desc->max)) return -EINVAL; for (i = 0; i < desc->count; i++) { - if (params->frequency > desc->entries[i].limit) + if (frequency > desc->entries[i].limit) continue; break; } if (debug) printk("pll: %s: freq=%d | i=%d/%d\n", desc->name, - params->frequency, i, desc->count); + frequency, i, desc->count); if (i == desc->count) return -EINVAL; - div = (params->frequency + desc->iffreq + + div = (frequency + desc->iffreq + desc->entries[i].stepsize/2) / desc->entries[i].stepsize; buf[0] = div >> 8; buf[1] = div & 0xff; @@ -568,7 +565,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, buf[3] = desc->entries[i].cb; if (desc->set) - desc->set(fe, buf, params); + desc->set(fe, buf); if (debug) printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", @@ -611,9 +608,9 @@ static int dvb_pll_sleep(struct dvb_frontend *fe) return -EINVAL; } -static int dvb_pll_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int dvb_pll_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_pll_priv *priv = fe->tuner_priv; u8 buf[4]; struct i2c_msg msg = @@ -625,7 +622,8 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, if (priv->i2c == NULL) return -EINVAL; - if ((result = dvb_pll_configure(fe, buf, params)) < 0) + result = dvb_pll_configure(fe, buf, c->frequency); + if (result < 0) return result; else frequency = result; @@ -637,15 +635,15 @@ static int dvb_pll_set_params(struct dvb_frontend *fe, } priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->bandwidth = c->bandwidth_hz; return 0; } static int dvb_pll_calc_regs(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, u8 *buf, int buf_len) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_pll_priv *priv = fe->tuner_priv; int result; u32 frequency = 0; @@ -653,7 +651,8 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, if (buf_len < 5) return -EINVAL; - if ((result = dvb_pll_configure(fe, buf+1, params)) < 0) + result = dvb_pll_configure(fe, buf + 1, c->frequency); + if (result < 0) return result; else frequency = result; @@ -661,7 +660,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe, buf[0] = priv->pll_i2c_address; priv->frequency = frequency; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; + priv->bandwidth = c->bandwidth_hz; return 5; } diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index a7fc7e53a551..dcfc902c8678 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -68,15 +68,18 @@ static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +/* + * Only needed if it actually reads something from the hardware + */ +static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe) { return 0; } -static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -171,10 +174,9 @@ error: } static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Dummy DVB-T", - .type = FE_OFDM, .frequency_min = 0, .frequency_max = 863250000, .frequency_stepsize = 62500, @@ -203,10 +205,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { }; static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "Dummy DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 51000000, .frequency_max = 858000000, @@ -233,10 +234,9 @@ static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { }; static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Dummy DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 250, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/ec100.c b/drivers/media/dvb/frontends/ec100.c index 2414dc6ee5d9..c56fddbf53b7 100644 --- a/drivers/media/dvb/frontends/ec100.c +++ b/drivers/media/dvb/frontends/ec100.c @@ -76,19 +76,19 @@ static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val) return 0; } -static int ec100_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int ec100_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct ec100_state *state = fe->demodulator_priv; int ret; u8 tmp, tmp2; - deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency, - params->u.ofdm.bandwidth); + deb_info("%s: freq:%d bw:%d\n", __func__, c->frequency, + c->bandwidth_hz); /* program tuner */ if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, params); + fe->ops.tuner_ops.set_params(fe); ret = ec100_write_reg(state, 0x04, 0x06); if (ret) @@ -108,16 +108,16 @@ static int ec100_set_frontend(struct dvb_frontend *fe, B 0x1b | 0xb7 | 0x00 | 0x49 B 0x1c | 0x55 | 0x64 | 0x72 */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: tmp = 0xb7; tmp2 = 0x55; break; - case BANDWIDTH_7_MHZ: + case 7000000: tmp = 0x00; tmp2 = 0x64; break; - case BANDWIDTH_8_MHZ: + case 8000000: default: tmp = 0x49; tmp2 = 0x72; @@ -306,9 +306,9 @@ error: EXPORT_SYMBOL(ec100_attach); static struct dvb_frontend_ops ec100_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "E3C EC100 DVB-T", - .type = FE_OFDM, .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 | diff --git a/drivers/media/dvb/frontends/hd29l2.c b/drivers/media/dvb/frontends/hd29l2.c new file mode 100644 index 000000000000..a00318190837 --- /dev/null +++ b/drivers/media/dvb/frontends/hd29l2.c @@ -0,0 +1,861 @@ +/* + * HDIC HD29L2 DMB-TH demodulator driver + * + * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D + * + * Author: Antti Palosaari <crope@iki.fi> + * + * 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. + * + * 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. + */ + +#include "hd29l2_priv.h" + +int hd29l2_debug; +module_param_named(debug, hd29l2_debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +/* write multiple registers */ +static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len) +{ + int ret; + u8 buf[2 + len]; + struct i2c_msg msg[1] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + buf[0] = 0x00; + buf[1] = reg; + memcpy(&buf[2], val, len); + + ret = i2c_transfer(priv->i2c, msg, 1); + if (ret == 1) { + ret = 0; + } else { + warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* read multiple registers */ +static int hd29l2_rd_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len) +{ + int ret; + u8 buf[2] = { 0x00, reg }; + struct i2c_msg msg[2] = { + { + .addr = priv->cfg.i2c_addr, + .flags = 0, + .len = 2, + .buf = buf, + }, { + .addr = priv->cfg.i2c_addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + } + }; + + ret = i2c_transfer(priv->i2c, msg, 2); + if (ret == 2) { + ret = 0; + } else { + warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len); + ret = -EREMOTEIO; + } + + return ret; +} + +/* write single register */ +static int hd29l2_wr_reg(struct hd29l2_priv *priv, u8 reg, u8 val) +{ + return hd29l2_wr_regs(priv, reg, &val, 1); +} + +/* read single register */ +static int hd29l2_rd_reg(struct hd29l2_priv *priv, u8 reg, u8 *val) +{ + return hd29l2_rd_regs(priv, reg, val, 1); +} + +/* write single register with mask */ +static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask) +{ + int ret; + u8 tmp; + + /* no need for read if whole reg is written */ + if (mask != 0xff) { + ret = hd29l2_rd_regs(priv, reg, &tmp, 1); + if (ret) + return ret; + + val &= mask; + tmp &= ~mask; + val |= tmp; + } + + return hd29l2_wr_regs(priv, reg, &val, 1); +} + +/* read single register with mask */ +int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask) +{ + int ret, i; + u8 tmp; + + ret = hd29l2_rd_regs(priv, reg, &tmp, 1); + if (ret) + return ret; + + tmp &= mask; + + /* find position of the first bit */ + for (i = 0; i < 8; i++) { + if ((mask >> i) & 0x01) + break; + } + *val = tmp >> i; + + return 0; +} + +static int hd29l2_soft_reset(struct hd29l2_priv *priv) +{ + int ret; + u8 tmp; + + ret = hd29l2_rd_reg(priv, 0x26, &tmp); + if (ret) + goto err; + + ret = hd29l2_wr_reg(priv, 0x26, 0x0d); + if (ret) + goto err; + + usleep_range(10000, 20000); + + ret = hd29l2_wr_reg(priv, 0x26, tmp); + if (ret) + goto err; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + int ret, i; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 tmp; + + dbg("%s: enable=%d", __func__, enable); + + /* set tuner address for demod */ + if (!priv->tuner_i2c_addr_programmed && enable) { + /* no need to set tuner address every time, once is enough */ + ret = hd29l2_wr_reg(priv, 0x9d, priv->cfg.tuner_i2c_addr << 1); + if (ret) + goto err; + + priv->tuner_i2c_addr_programmed = true; + } + + /* open / close gate */ + ret = hd29l2_wr_reg(priv, 0x9f, enable); + if (ret) + goto err; + + /* wait demod ready */ + for (i = 10; i; i--) { + ret = hd29l2_rd_reg(priv, 0x9e, &tmp); + if (ret) + goto err; + + if (tmp == enable) + break; + + usleep_range(5000, 10000); + } + + dbg("%s: loop=%d", __func__, i); + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + + *status = 0; + + ret = hd29l2_rd_reg(priv, 0x05, &buf[0]); + if (ret) + goto err; + + if (buf[0] & 0x01) { + /* full lock */ + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + } else { + ret = hd29l2_rd_reg(priv, 0x0d, &buf[1]); + if (ret) + goto err; + + if ((buf[1] & 0xfe) == 0x78) + /* partial lock */ + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC; + } + + priv->fe_status = *status; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + u16 tmp; + + if (!(priv->fe_status & FE_HAS_LOCK)) { + *snr = 0; + ret = 0; + goto err; + } + + ret = hd29l2_rd_regs(priv, 0x0b, buf, 2); + if (ret) + goto err; + + tmp = (buf[0] << 8) | buf[1]; + + /* report SNR in dB * 10 */ + #define LOG10_20736_24 72422627 /* log10(20736) << 24 */ + if (tmp) + *snr = (LOG10_20736_24 - intlog10(tmp)) / ((1 << 24) / 100); + else + *snr = 0; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + u16 tmp; + + *strength = 0; + + ret = hd29l2_rd_regs(priv, 0xd5, buf, 2); + if (ret) + goto err; + + tmp = buf[0] << 8 | buf[1]; + tmp = ~tmp & 0x0fff; + + /* scale value to 0x0000-0xffff from 0x0000-0x0fff */ + *strength = tmp * 0xffff / 0x0fff; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 buf[2]; + + if (!(priv->fe_status & FE_HAS_SYNC)) { + *ber = 0; + ret = 0; + goto err; + } + + ret = hd29l2_rd_regs(priv, 0xd9, buf, 2); + if (ret) { + *ber = 0; + goto err; + } + + /* LDPC BER */ + *ber = ((buf[0] & 0x0f) << 8) | buf[1]; + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + /* no way to read? */ + *ucblocks = 0; + return 0; +} + +static enum dvbfe_search hd29l2_search(struct dvb_frontend *fe) +{ + int ret, i; + struct hd29l2_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 tmp, buf[3]; + u8 modulation, carrier, guard_interval, interleave, code_rate; + u64 num64; + u32 if_freq, if_ctl; + bool auto_mode; + + dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d " \ + "modulation=%d inversion=%d fec_inner=%d guard_interval=%d", + __func__, + c->delivery_system, c->frequency, c->bandwidth_hz, + c->modulation, c->inversion, c->fec_inner, c->guard_interval); + + /* as for now we detect always params automatically */ + auto_mode = true; + + /* program tuner */ + if (fe->ops.tuner_ops.set_params) + fe->ops.tuner_ops.set_params(fe); + + /* get and program IF */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + else + if_freq = 0; + + if (if_freq) { + /* normal IF */ + + /* calc IF control value */ + num64 = if_freq; + num64 *= 0x800000; + num64 = div_u64(num64, HD29L2_XTAL); + num64 -= 0x800000; + if_ctl = num64; + + tmp = 0xfc; /* tuner type normal */ + } else { + /* zero IF */ + if_ctl = 0; + tmp = 0xfe; /* tuner type Zero-IF */ + } + + buf[0] = ((if_ctl >> 0) & 0xff); + buf[1] = ((if_ctl >> 8) & 0xff); + buf[2] = ((if_ctl >> 16) & 0xff); + + /* program IF control */ + ret = hd29l2_wr_regs(priv, 0x14, buf, 3); + if (ret) + goto err; + + /* program tuner type */ + ret = hd29l2_wr_reg(priv, 0xab, tmp); + if (ret) + goto err; + + dbg("%s: if_freq=%d if_ctl=%x", __func__, if_freq, if_ctl); + + if (auto_mode) { + /* + * use auto mode + */ + + /* disable quick mode */ + ret = hd29l2_wr_reg_mask(priv, 0xac, 0 << 7, 0x80); + if (ret) + goto err; + + ret = hd29l2_wr_reg_mask(priv, 0x82, 1 << 1, 0x02); + if (ret) + goto err; + + /* enable auto mode */ + ret = hd29l2_wr_reg_mask(priv, 0x7d, 1 << 6, 0x40); + if (ret) + goto err; + + ret = hd29l2_wr_reg_mask(priv, 0x81, 1 << 3, 0x08); + if (ret) + goto err; + + /* soft reset */ + ret = hd29l2_soft_reset(priv); + if (ret) + goto err; + + /* detect modulation */ + for (i = 30; i; i--) { + msleep(100); + + ret = hd29l2_rd_reg(priv, 0x0d, &tmp); + if (ret) + goto err; + + if ((((tmp & 0xf0) >= 0x10) && + ((tmp & 0x0f) == 0x08)) || (tmp >= 0x2c)) + break; + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) + /* detection failed */ + return DVBFE_ALGO_SEARCH_FAILED; + + /* read modulation */ + ret = hd29l2_rd_reg_mask(priv, 0x7d, &modulation, 0x07); + if (ret) + goto err; + } else { + /* + * use manual mode + */ + + modulation = HD29L2_QAM64; + carrier = HD29L2_CARRIER_MULTI; + guard_interval = HD29L2_PN945; + interleave = HD29L2_INTERLEAVER_420; + code_rate = HD29L2_CODE_RATE_08; + + tmp = (code_rate << 3) | modulation; + ret = hd29l2_wr_reg_mask(priv, 0x7d, tmp, 0x5f); + if (ret) + goto err; + + tmp = (carrier << 2) | guard_interval; + ret = hd29l2_wr_reg_mask(priv, 0x81, tmp, 0x0f); + if (ret) + goto err; + + tmp = interleave; + ret = hd29l2_wr_reg_mask(priv, 0x82, tmp, 0x03); + if (ret) + goto err; + } + + /* ensure modulation validy */ + /* 0=QAM4_NR, 1=QAM4, 2=QAM16, 3=QAM32, 4=QAM64 */ + if (modulation > (ARRAY_SIZE(reg_mod_vals_tab[0].val) - 1)) { + dbg("%s: modulation=%d not valid", __func__, modulation); + goto err; + } + + /* program registers according to modulation */ + for (i = 0; i < ARRAY_SIZE(reg_mod_vals_tab); i++) { + ret = hd29l2_wr_reg(priv, reg_mod_vals_tab[i].reg, + reg_mod_vals_tab[i].val[modulation]); + if (ret) + goto err; + } + + /* read guard interval */ + ret = hd29l2_rd_reg_mask(priv, 0x81, &guard_interval, 0x03); + if (ret) + goto err; + + /* read carrier mode */ + ret = hd29l2_rd_reg_mask(priv, 0x81, &carrier, 0x04); + if (ret) + goto err; + + dbg("%s: modulation=%d guard_interval=%d carrier=%d", + __func__, modulation, guard_interval, carrier); + + if ((carrier == HD29L2_CARRIER_MULTI) && (modulation == HD29L2_QAM64) && + (guard_interval == HD29L2_PN945)) { + dbg("%s: C=3780 && QAM64 && PN945", __func__); + + ret = hd29l2_wr_reg(priv, 0x42, 0x33); + if (ret) + goto err; + + ret = hd29l2_wr_reg(priv, 0xdd, 0x01); + if (ret) + goto err; + } + + usleep_range(10000, 20000); + + /* soft reset */ + ret = hd29l2_soft_reset(priv); + if (ret) + goto err; + + /* wait demod lock */ + for (i = 30; i; i--) { + msleep(100); + + /* read lock bit */ + ret = hd29l2_rd_reg_mask(priv, 0x05, &tmp, 0x01); + if (ret) + goto err; + + if (tmp) + break; + } + + dbg("%s: loop=%d", __func__, i); + + if (i == 0) + return DVBFE_ALGO_SEARCH_AGAIN; + + return DVBFE_ALGO_SEARCH_SUCCESS; +err: + dbg("%s: failed=%d", __func__, ret); + return DVBFE_ALGO_SEARCH_ERROR; +} + +static int hd29l2_get_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static int hd29l2_get_frontend(struct dvb_frontend *fe) +{ + int ret; + struct hd29l2_priv *priv = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u8 buf[3]; + u32 if_ctl; + char *str_constellation, *str_code_rate, *str_constellation_code_rate, + *str_guard_interval, *str_carrier, *str_guard_interval_carrier, + *str_interleave, *str_interleave_; + + ret = hd29l2_rd_reg(priv, 0x7d, &buf[0]); + if (ret) + goto err; + + ret = hd29l2_rd_regs(priv, 0x81, &buf[1], 2); + if (ret) + goto err; + + /* constellation, 0x7d[2:0] */ + switch ((buf[0] >> 0) & 0x07) { + case 0: /* QAM4NR */ + str_constellation = "QAM4NR"; + c->modulation = QAM_AUTO; /* FIXME */ + break; + case 1: /* QAM4 */ + str_constellation = "QAM4"; + c->modulation = QPSK; /* FIXME */ + break; + case 2: + str_constellation = "QAM16"; + c->modulation = QAM_16; + break; + case 3: + str_constellation = "QAM32"; + c->modulation = QAM_32; + break; + case 4: + str_constellation = "QAM64"; + c->modulation = QAM_64; + break; + default: + str_constellation = "?"; + } + + /* LDPC code rate, 0x7d[4:3] */ + switch ((buf[0] >> 3) & 0x03) { + case 0: /* 0.4 */ + str_code_rate = "0.4"; + c->fec_inner = FEC_AUTO; /* FIXME */ + break; + case 1: /* 0.6 */ + str_code_rate = "0.6"; + c->fec_inner = FEC_3_5; + break; + case 2: /* 0.8 */ + str_code_rate = "0.8"; + c->fec_inner = FEC_4_5; + break; + default: + str_code_rate = "?"; + } + + /* constellation & code rate set, 0x7d[6] */ + switch ((buf[0] >> 6) & 0x01) { + case 0: + str_constellation_code_rate = "manual"; + break; + case 1: + str_constellation_code_rate = "auto"; + break; + default: + str_constellation_code_rate = "?"; + } + + /* frame header, 0x81[1:0] */ + switch ((buf[1] >> 0) & 0x03) { + case 0: /* PN945 */ + str_guard_interval = "PN945"; + c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */ + break; + case 1: /* PN595 */ + str_guard_interval = "PN595"; + c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */ + break; + case 2: /* PN420 */ + str_guard_interval = "PN420"; + c->guard_interval = GUARD_INTERVAL_AUTO; /* FIXME */ + break; + default: + str_guard_interval = "?"; + } + + /* carrier, 0x81[2] */ + switch ((buf[1] >> 2) & 0x01) { + case 0: + str_carrier = "C=1"; + break; + case 1: + str_carrier = "C=3780"; + break; + default: + str_carrier = "?"; + } + + /* frame header & carrier set, 0x81[3] */ + switch ((buf[1] >> 3) & 0x01) { + case 0: + str_guard_interval_carrier = "manual"; + break; + case 1: + str_guard_interval_carrier = "auto"; + break; + default: + str_guard_interval_carrier = "?"; + } + + /* interleave, 0x82[0] */ + switch ((buf[2] >> 0) & 0x01) { + case 0: + str_interleave = "M=720"; + break; + case 1: + str_interleave = "M=240"; + break; + default: + str_interleave = "?"; + } + + /* interleave set, 0x82[1] */ + switch ((buf[2] >> 1) & 0x01) { + case 0: + str_interleave_ = "manual"; + break; + case 1: + str_interleave_ = "auto"; + break; + default: + str_interleave_ = "?"; + } + + /* + * We can read out current detected NCO and use that value next + * time instead of calculating new value from targed IF. + * I think it will not effect receiver sensitivity but gaining lock + * after tune could be easier... + */ + ret = hd29l2_rd_regs(priv, 0xb1, &buf[0], 3); + if (ret) + goto err; + + if_ctl = (buf[0] << 16) | ((buf[1] - 7) << 8) | buf[2]; + + dbg("%s: %s %s %s | %s %s %s | %s %s | NCO=%06x", __func__, + str_constellation, str_code_rate, str_constellation_code_rate, + str_guard_interval, str_carrier, str_guard_interval_carrier, + str_interleave, str_interleave_, if_ctl); + + return 0; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static int hd29l2_init(struct dvb_frontend *fe) +{ + int ret, i; + struct hd29l2_priv *priv = fe->demodulator_priv; + u8 tmp; + static const struct reg_val tab[] = { + { 0x3a, 0x06 }, + { 0x3b, 0x03 }, + { 0x3c, 0x04 }, + { 0xaf, 0x06 }, + { 0xb0, 0x1b }, + { 0x80, 0x64 }, + { 0x10, 0x38 }, + }; + + dbg("%s:", __func__); + + /* reset demod */ + /* it is recommended to HW reset chip using RST_N pin */ + if (fe->callback) { + ret = fe->callback(fe, DVB_FRONTEND_COMPONENT_DEMOD, 0, 0); + if (ret) + goto err; + + /* reprogramming needed because HW reset clears registers */ + priv->tuner_i2c_addr_programmed = false; + } + + /* init */ + for (i = 0; i < ARRAY_SIZE(tab); i++) { + ret = hd29l2_wr_reg(priv, tab[i].reg, tab[i].val); + if (ret) + goto err; + } + + /* TS params */ + ret = hd29l2_rd_reg(priv, 0x36, &tmp); + if (ret) + goto err; + + tmp &= 0x1b; + tmp |= priv->cfg.ts_mode; + ret = hd29l2_wr_reg(priv, 0x36, tmp); + if (ret) + goto err; + + ret = hd29l2_rd_reg(priv, 0x31, &tmp); + tmp &= 0xef; + + if (!(priv->cfg.ts_mode >> 7)) + /* set b4 for serial TS */ + tmp |= 0x10; + + ret = hd29l2_wr_reg(priv, 0x31, tmp); + if (ret) + goto err; + + return ret; +err: + dbg("%s: failed=%d", __func__, ret); + return ret; +} + +static void hd29l2_release(struct dvb_frontend *fe) +{ + struct hd29l2_priv *priv = fe->demodulator_priv; + kfree(priv); +} + +static struct dvb_frontend_ops hd29l2_ops; + +struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, + struct i2c_adapter *i2c) +{ + int ret; + struct hd29l2_priv *priv = NULL; + u8 tmp; + + /* allocate memory for the internal state */ + priv = kzalloc(sizeof(struct hd29l2_priv), GFP_KERNEL); + if (priv == NULL) + goto err; + + /* setup the state */ + priv->i2c = i2c; + memcpy(&priv->cfg, config, sizeof(struct hd29l2_config)); + + + /* check if the demod is there */ + ret = hd29l2_rd_reg(priv, 0x00, &tmp); + if (ret) + goto err; + + /* create dvb_frontend */ + memcpy(&priv->fe.ops, &hd29l2_ops, sizeof(struct dvb_frontend_ops)); + priv->fe.demodulator_priv = priv; + + return &priv->fe; +err: + kfree(priv); + return NULL; +} +EXPORT_SYMBOL(hd29l2_attach); + +static struct dvb_frontend_ops hd29l2_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "HDIC HD29L2 DMB-TH", + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_BANDWIDTH_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER + }, + + .release = hd29l2_release, + + .init = hd29l2_init, + + .get_frontend_algo = hd29l2_get_frontend_algo, + .search = hd29l2_search, + .get_frontend = hd29l2_get_frontend, + + .read_status = hd29l2_read_status, + .read_snr = hd29l2_read_snr, + .read_signal_strength = hd29l2_read_signal_strength, + .read_ber = hd29l2_read_ber, + .read_ucblocks = hd29l2_read_ucblocks, + + .i2c_gate_ctrl = hd29l2_i2c_gate_ctrl, +}; + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("HDIC HD29L2 DMB-TH demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/hd29l2.h b/drivers/media/dvb/frontends/hd29l2.h new file mode 100644 index 000000000000..a7a64431364d --- /dev/null +++ b/drivers/media/dvb/frontends/hd29l2.h @@ -0,0 +1,66 @@ +/* + * HDIC HD29L2 DMB-TH demodulator driver + * + * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D + * + * Author: Antti Palosaari <crope@iki.fi> + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HD29L2_H +#define HD29L2_H + +#include <linux/dvb/frontend.h> + +struct hd29l2_config { + /* + * demodulator I2C address + */ + u8 i2c_addr; + + /* + * tuner I2C address + * only needed when tuner is behind demod I2C-gate + */ + u8 tuner_i2c_addr; + + /* + * TS settings + */ +#define HD29L2_TS_SERIAL 0x00 +#define HD29L2_TS_PARALLEL 0x80 +#define HD29L2_TS_CLK_NORMAL 0x40 +#define HD29L2_TS_CLK_INVERTED 0x00 +#define HD29L2_TS_CLK_GATED 0x20 +#define HD29L2_TS_CLK_FREE 0x00 + u8 ts_mode; +}; + + +#if defined(CONFIG_DVB_HD29L2) || \ + (defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE)) +extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *hd29l2_attach( +const struct hd29l2_config *config, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* HD29L2_H */ diff --git a/drivers/media/dvb/frontends/hd29l2_priv.h b/drivers/media/dvb/frontends/hd29l2_priv.h new file mode 100644 index 000000000000..ba16dc3ec2bd --- /dev/null +++ b/drivers/media/dvb/frontends/hd29l2_priv.h @@ -0,0 +1,314 @@ +/* + * HDIC HD29L2 DMB-TH demodulator driver + * + * Copyright (C) 2011 Metropolia University of Applied Sciences, Electria R&D + * + * Author: Antti Palosaari <crope@iki.fi> + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef HD29L2_PRIV +#define HD29L2_PRIV + +#include <linux/dvb/version.h> +#include "dvb_frontend.h" +#include "dvb_math.h" +#include "hd29l2.h" + +#define LOG_PREFIX "hd29l2" + +#undef dbg +#define dbg(f, arg...) \ + if (hd29l2_debug) \ + printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef err +#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) +#undef info +#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) +#undef warn +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) + +#define HD29L2_XTAL 30400000 /* Hz */ + + +#define HD29L2_QAM4NR 0x00 +#define HD29L2_QAM4 0x01 +#define HD29L2_QAM16 0x02 +#define HD29L2_QAM32 0x03 +#define HD29L2_QAM64 0x04 + +#define HD29L2_CODE_RATE_04 0x00 +#define HD29L2_CODE_RATE_06 0x08 +#define HD29L2_CODE_RATE_08 0x10 + +#define HD29L2_PN945 0x00 +#define HD29L2_PN595 0x01 +#define HD29L2_PN420 0x02 + +#define HD29L2_CARRIER_SINGLE 0x00 +#define HD29L2_CARRIER_MULTI 0x01 + +#define HD29L2_INTERLEAVER_720 0x00 +#define HD29L2_INTERLEAVER_420 0x01 + +struct reg_val { + u8 reg; + u8 val; +}; + +struct reg_mod_vals { + u8 reg; + u8 val[5]; +}; + +struct hd29l2_priv { + struct i2c_adapter *i2c; + struct dvb_frontend fe; + struct hd29l2_config cfg; + u8 tuner_i2c_addr_programmed:1; + + fe_status_t fe_status; +}; + +static const struct reg_mod_vals reg_mod_vals_tab[] = { + /* REG, QAM4NR, QAM4,QAM16,QAM32,QAM64 */ + { 0x01, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x02, { 0x07, 0x07, 0x07, 0x07, 0x07 } }, + { 0x03, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x04, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x05, { 0x61, 0x60, 0x60, 0x61, 0x60 } }, + { 0x06, { 0xff, 0xff, 0xff, 0xff, 0xff } }, + { 0x07, { 0xff, 0xff, 0xff, 0xff, 0xff } }, + { 0x08, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x09, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x0a, { 0x15, 0x15, 0x03, 0x03, 0x03 } }, + { 0x0d, { 0x78, 0x78, 0x88, 0x78, 0x78 } }, + { 0x0e, { 0xa0, 0x90, 0xa0, 0xa0, 0xa0 } }, + { 0x0f, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x10, { 0xa0, 0xa0, 0x58, 0x38, 0x38 } }, + { 0x11, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x12, { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a } }, + { 0x13, { 0xa2, 0xa2, 0xa2, 0xa2, 0xa2 } }, + { 0x17, { 0x40, 0x40, 0x40, 0x40, 0x40 } }, + { 0x18, { 0x21, 0x21, 0x42, 0x52, 0x42 } }, + { 0x19, { 0x21, 0x21, 0x62, 0x72, 0x62 } }, + { 0x1a, { 0x32, 0x43, 0xa9, 0xb9, 0xa9 } }, + { 0x1b, { 0x32, 0x43, 0xb9, 0xd8, 0xb9 } }, + { 0x1c, { 0x02, 0x02, 0x03, 0x02, 0x03 } }, + { 0x1d, { 0x0c, 0x0c, 0x01, 0x02, 0x02 } }, + { 0x1e, { 0x02, 0x02, 0x02, 0x01, 0x02 } }, + { 0x1f, { 0x02, 0x02, 0x01, 0x02, 0x04 } }, + { 0x20, { 0x01, 0x02, 0x01, 0x01, 0x01 } }, + { 0x21, { 0x08, 0x08, 0x0a, 0x0a, 0x0a } }, + { 0x22, { 0x06, 0x06, 0x04, 0x05, 0x05 } }, + { 0x23, { 0x06, 0x06, 0x05, 0x03, 0x05 } }, + { 0x24, { 0x08, 0x08, 0x05, 0x07, 0x07 } }, + { 0x25, { 0x16, 0x10, 0x10, 0x0a, 0x10 } }, + { 0x26, { 0x14, 0x14, 0x04, 0x04, 0x04 } }, + { 0x27, { 0x58, 0x58, 0x58, 0x5c, 0x58 } }, + { 0x28, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0x29, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0x2a, { 0x08, 0x0a, 0x08, 0x08, 0x08 } }, + { 0x2b, { 0x08, 0x08, 0x08, 0x08, 0x08 } }, + { 0x2c, { 0x06, 0x06, 0x06, 0x06, 0x06 } }, + { 0x2d, { 0x05, 0x06, 0x06, 0x06, 0x06 } }, + { 0x2e, { 0x21, 0x21, 0x21, 0x21, 0x21 } }, + { 0x2f, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x30, { 0x14, 0x14, 0x14, 0x14, 0x14 } }, + { 0x33, { 0xb7, 0xb7, 0xb7, 0xb7, 0xb7 } }, + { 0x34, { 0x81, 0x81, 0x81, 0x81, 0x81 } }, + { 0x35, { 0x80, 0x80, 0x80, 0x80, 0x80 } }, + { 0x37, { 0x70, 0x70, 0x70, 0x70, 0x70 } }, + { 0x38, { 0x04, 0x04, 0x02, 0x02, 0x02 } }, + { 0x39, { 0x07, 0x07, 0x05, 0x05, 0x05 } }, + { 0x3a, { 0x06, 0x06, 0x06, 0x06, 0x06 } }, + { 0x3b, { 0x03, 0x03, 0x03, 0x03, 0x03 } }, + { 0x3c, { 0x07, 0x06, 0x04, 0x04, 0x04 } }, + { 0x3d, { 0xf0, 0xf0, 0xf0, 0xf0, 0x80 } }, + { 0x3e, { 0x60, 0x60, 0x60, 0x60, 0xff } }, + { 0x3f, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x40, { 0x5b, 0x5b, 0x5b, 0x57, 0x50 } }, + { 0x41, { 0x30, 0x30, 0x30, 0x30, 0x18 } }, + { 0x42, { 0x20, 0x20, 0x20, 0x00, 0x30 } }, + { 0x43, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x44, { 0x3f, 0x3f, 0x3f, 0x3f, 0x3f } }, + { 0x45, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x46, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0x47, { 0x00, 0x00, 0x95, 0x00, 0x95 } }, + { 0x48, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } }, + { 0x49, { 0xc0, 0xc0, 0xc0, 0xc0, 0xc0 } }, + { 0x4a, { 0x40, 0x40, 0x33, 0x11, 0x11 } }, + { 0x4b, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x4c, { 0x40, 0x40, 0x99, 0x11, 0x11 } }, + { 0x4d, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x4e, { 0x40, 0x40, 0x66, 0x77, 0x77 } }, + { 0x4f, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x50, { 0x40, 0x40, 0x88, 0x33, 0x11 } }, + { 0x51, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x52, { 0x40, 0x40, 0x88, 0x02, 0x02 } }, + { 0x53, { 0x40, 0x40, 0x00, 0x02, 0x02 } }, + { 0x54, { 0x00, 0x00, 0x88, 0x33, 0x33 } }, + { 0x55, { 0x40, 0x40, 0x00, 0x00, 0x00 } }, + { 0x56, { 0x00, 0x00, 0x00, 0x0b, 0x00 } }, + { 0x57, { 0x40, 0x40, 0x0a, 0x0b, 0x0a } }, + { 0x58, { 0xaa, 0x00, 0x00, 0x00, 0x00 } }, + { 0x59, { 0x7a, 0x40, 0x02, 0x02, 0x02 } }, + { 0x5a, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5b, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5c, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5d, { 0x18, 0x18, 0x01, 0x01, 0x01 } }, + { 0x5e, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } }, + { 0x5f, { 0xc0, 0xc0, 0xc0, 0xff, 0xc0 } }, + { 0x60, { 0x40, 0x40, 0x00, 0x30, 0x30 } }, + { 0x61, { 0x40, 0x40, 0x10, 0x30, 0x30 } }, + { 0x62, { 0x40, 0x40, 0x00, 0x30, 0x30 } }, + { 0x63, { 0x40, 0x40, 0x05, 0x30, 0x30 } }, + { 0x64, { 0x40, 0x40, 0x06, 0x00, 0x30 } }, + { 0x65, { 0x40, 0x40, 0x06, 0x08, 0x30 } }, + { 0x66, { 0x40, 0x40, 0x00, 0x00, 0x20 } }, + { 0x67, { 0x40, 0x40, 0x01, 0x04, 0x20 } }, + { 0x68, { 0x00, 0x00, 0x30, 0x00, 0x20 } }, + { 0x69, { 0xa0, 0xa0, 0x00, 0x08, 0x20 } }, + { 0x6a, { 0x00, 0x00, 0x30, 0x00, 0x25 } }, + { 0x6b, { 0xa0, 0xa0, 0x00, 0x06, 0x25 } }, + { 0x6c, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x6d, { 0xa0, 0x60, 0x0c, 0x03, 0x0c } }, + { 0x6e, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x6f, { 0xa0, 0x60, 0x04, 0x01, 0x04 } }, + { 0x70, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } }, + { 0x71, { 0x58, 0x58, 0xaa, 0xaa, 0xaa } }, + { 0x72, { 0x58, 0x58, 0xff, 0xff, 0xff } }, + { 0x73, { 0x58, 0x58, 0xff, 0xff, 0xff } }, + { 0x74, { 0x06, 0x06, 0x09, 0x05, 0x05 } }, + { 0x75, { 0x06, 0x06, 0x0a, 0x10, 0x10 } }, + { 0x76, { 0x10, 0x10, 0x06, 0x0a, 0x0a } }, + { 0x77, { 0x12, 0x18, 0x28, 0x10, 0x28 } }, + { 0x78, { 0xf8, 0xf8, 0xf8, 0xf8, 0xf8 } }, + { 0x79, { 0x15, 0x15, 0x03, 0x03, 0x03 } }, + { 0x7a, { 0x02, 0x02, 0x01, 0x04, 0x03 } }, + { 0x7b, { 0x01, 0x02, 0x03, 0x03, 0x03 } }, + { 0x7c, { 0x28, 0x28, 0x28, 0x28, 0x28 } }, + { 0x7f, { 0x25, 0x92, 0x5f, 0x17, 0x2d } }, + { 0x80, { 0x64, 0x64, 0x64, 0x74, 0x64 } }, + { 0x83, { 0x06, 0x03, 0x04, 0x04, 0x04 } }, + { 0x84, { 0xff, 0xff, 0xff, 0xff, 0xff } }, + { 0x85, { 0x05, 0x05, 0x05, 0x05, 0x05 } }, + { 0x86, { 0x00, 0x00, 0x11, 0x11, 0x11 } }, + { 0x87, { 0x03, 0x03, 0x03, 0x03, 0x03 } }, + { 0x88, { 0x09, 0x09, 0x09, 0x09, 0x09 } }, + { 0x89, { 0x20, 0x20, 0x30, 0x20, 0x20 } }, + { 0x8a, { 0x03, 0x03, 0x02, 0x03, 0x02 } }, + { 0x8b, { 0x00, 0x07, 0x09, 0x00, 0x09 } }, + { 0x8c, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x8d, { 0x4f, 0x4f, 0x4f, 0x3f, 0x4f } }, + { 0x8e, { 0xf0, 0xf0, 0x60, 0xf0, 0xa0 } }, + { 0x8f, { 0xe8, 0xe8, 0xe8, 0xe8, 0xe8 } }, + { 0x90, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x91, { 0x40, 0x40, 0x70, 0x70, 0x10 } }, + { 0x92, { 0x00, 0x00, 0x00, 0x00, 0x04 } }, + { 0x93, { 0x60, 0x60, 0x60, 0x60, 0x60 } }, + { 0x94, { 0x00, 0x00, 0x00, 0x00, 0x03 } }, + { 0x95, { 0x09, 0x09, 0x47, 0x47, 0x47 } }, + { 0x96, { 0x80, 0xa0, 0xa0, 0x40, 0xa0 } }, + { 0x97, { 0x60, 0x60, 0x60, 0x60, 0x60 } }, + { 0x98, { 0x50, 0x50, 0x50, 0x30, 0x50 } }, + { 0x99, { 0x10, 0x10, 0x10, 0x10, 0x10 } }, + { 0x9a, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0x9b, { 0x40, 0x40, 0x40, 0x30, 0x40 } }, + { 0x9c, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa0, { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 } }, + { 0xa1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa2, { 0x30, 0x30, 0x00, 0x30, 0x00 } }, + { 0xa3, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa4, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa5, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa6, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa7, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xa8, { 0x77, 0x77, 0x77, 0x77, 0x77 } }, + { 0xa9, { 0x02, 0x02, 0x02, 0x02, 0x02 } }, + { 0xaa, { 0x40, 0x40, 0x40, 0x40, 0x40 } }, + { 0xac, { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f } }, + { 0xad, { 0x14, 0x14, 0x14, 0x14, 0x14 } }, + { 0xae, { 0x78, 0x78, 0x78, 0x78, 0x78 } }, + { 0xaf, { 0x06, 0x06, 0x06, 0x06, 0x07 } }, + { 0xb0, { 0x1b, 0x1b, 0x1b, 0x19, 0x1b } }, + { 0xb1, { 0x18, 0x17, 0x17, 0x18, 0x17 } }, + { 0xb2, { 0x35, 0x82, 0x82, 0x38, 0x82 } }, + { 0xb3, { 0xb6, 0xce, 0xc7, 0x5c, 0xb0 } }, + { 0xb4, { 0x3f, 0x3e, 0x3e, 0x3f, 0x3e } }, + { 0xb5, { 0x70, 0x58, 0x50, 0x68, 0x50 } }, + { 0xb6, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xb7, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xb8, { 0x03, 0x03, 0x01, 0x01, 0x01 } }, + { 0xb9, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xba, { 0x06, 0x06, 0x0a, 0x05, 0x0a } }, + { 0xbb, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbc, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbd, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbe, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xbf, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc2, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc3, { 0x00, 0x00, 0x88, 0x66, 0x88 } }, + { 0xc4, { 0x10, 0x10, 0x00, 0x00, 0x00 } }, + { 0xc5, { 0x00, 0x00, 0x44, 0x60, 0x44 } }, + { 0xc6, { 0x10, 0x0a, 0x00, 0x00, 0x00 } }, + { 0xc7, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc8, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xc9, { 0x90, 0x04, 0x00, 0x00, 0x00 } }, + { 0xca, { 0x90, 0x08, 0x01, 0x01, 0x01 } }, + { 0xcb, { 0xa0, 0x04, 0x00, 0x44, 0x00 } }, + { 0xcc, { 0xa0, 0x10, 0x03, 0x00, 0x03 } }, + { 0xcd, { 0x06, 0x06, 0x06, 0x05, 0x06 } }, + { 0xce, { 0x05, 0x05, 0x01, 0x01, 0x01 } }, + { 0xcf, { 0x40, 0x20, 0x18, 0x18, 0x18 } }, + { 0xd0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd2, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd3, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xd4, { 0x05, 0x05, 0x05, 0x05, 0x05 } }, + { 0xd5, { 0x05, 0x05, 0x05, 0x03, 0x05 } }, + { 0xd6, { 0xac, 0x22, 0xca, 0x8f, 0xca } }, + { 0xd7, { 0x20, 0x20, 0x20, 0x20, 0x20 } }, + { 0xd8, { 0x01, 0x01, 0x01, 0x01, 0x01 } }, + { 0xd9, { 0x00, 0x00, 0x0f, 0x00, 0x0f } }, + { 0xda, { 0x00, 0xff, 0xff, 0x0e, 0xff } }, + { 0xdb, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xdc, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xdd, { 0x05, 0x05, 0x05, 0x05, 0x05 } }, + { 0xde, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xdf, { 0x42, 0x42, 0x44, 0x44, 0x04 } }, + { 0xe0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe1, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe2, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe3, { 0x00, 0x00, 0x26, 0x06, 0x26 } }, + { 0xe4, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe5, { 0x01, 0x0a, 0x01, 0x01, 0x01 } }, + { 0xe6, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xe7, { 0x08, 0x08, 0x08, 0x08, 0x08 } }, + { 0xe8, { 0x63, 0x63, 0x63, 0x63, 0x63 } }, + { 0xe9, { 0x59, 0x59, 0x59, 0x59, 0x59 } }, + { 0xea, { 0x80, 0x80, 0x20, 0x80, 0x80 } }, + { 0xeb, { 0x37, 0x37, 0x78, 0x37, 0x77 } }, + { 0xec, { 0x1f, 0x1f, 0x25, 0x25, 0x25 } }, + { 0xed, { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a } }, + { 0xee, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { 0xef, { 0x70, 0x70, 0x58, 0x38, 0x58 } }, + { 0xf0, { 0x00, 0x00, 0x00, 0x00, 0x00 } }, +}; + +#endif /* HD29L2_PRIV */ diff --git a/drivers/media/dvb/frontends/it913x-fe-priv.h b/drivers/media/dvb/frontends/it913x-fe-priv.h index 1c6fb4b66255..93b086ea7e1c 100644 --- a/drivers/media/dvb/frontends/it913x-fe-priv.h +++ b/drivers/media/dvb/frontends/it913x-fe-priv.h @@ -22,126 +22,126 @@ struct adctable { u32 adcFrequency; /* clock and coeff tables only table 3 is used with IT9137*/ /* TODO other tables relate AF9035 may be removed */ static struct adctable tab1[] = { - { 20156250, BANDWIDTH_6_MHZ, + { 20156250, 6000000, 0x02b8ba6e, 0x015c5d37, 0x00ae340d, 0x00ae2e9b, 0x00ae292a, 0x015c5d37, 0x00ae2e9b, 0x0057174e, 0x02f1, 0x015c }, - { 20156250, BANDWIDTH_7_MHZ, + { 20156250, 7000000, 0x032cd980, 0x01966cc0, 0x00cb3cba, 0x00cb3660, 0x00cb3007, 0x01966cc0, 0x00cb3660, 0x00659b30, 0x0285, 0x0196 }, - { 20156250, BANDWIDTH_8_MHZ, + { 20156250, 8000000, 0x03a0f893, 0x01d07c49, 0x00e84567, 0x00e83e25, 0x00e836e3, 0x01d07c49, 0x00e83e25, 0x00741f12, 0x0234, 0x01d0 }, - { 20156250, BANDWIDTH_5_MHZ, + { 20156250, 5000000, 0x02449b5c, 0x01224dae, 0x00912b60, 0x009126d7, 0x0091224e, 0x01224dae, 0x009126d7, 0x0048936b, 0x0387, 0x0122 } }; static struct adctable tab2[] = { - { 20187500, BANDWIDTH_6_MHZ, + { 20187500, 6000000, 0x02b7a654, 0x015bd32a, 0x00adef04, 0x00ade995, 0x00ade426, 0x015bd32a, 0x00ade995, 0x0056f4ca, 0x02f2, 0x015c }, - { 20187500, BANDWIDTH_7_MHZ, + { 20187500, 7000000, 0x032b9761, 0x0195cbb1, 0x00caec30, 0x00cae5d8, 0x00cadf81, 0x0195cbb1, 0x00cae5d8, 0x006572ec, 0x0286, 0x0196 }, - { 20187500, BANDWIDTH_8_MHZ, + { 20187500, 8000000, 0x039f886f, 0x01cfc438, 0x00e7e95b, 0x00e7e21c, 0x00e7dadd, 0x01cfc438, 0x00e7e21c, 0x0073f10e, 0x0235, 0x01d0 }, - { 20187500, BANDWIDTH_5_MHZ, + { 20187500, 5000000, 0x0243b546, 0x0121daa3, 0x0090f1d9, 0x0090ed51, 0x0090e8ca, 0x0121daa3, 0x0090ed51, 0x004876a9, 0x0388, 0x0122 } }; static struct adctable tab3[] = { - { 20250000, BANDWIDTH_6_MHZ, + { 20250000, 6000000, 0x02b580ad, 0x015ac057, 0x00ad6597, 0x00ad602b, 0x00ad5ac1, 0x015ac057, 0x00ad602b, 0x0056b016, 0x02f4, 0x015b }, - { 20250000, BANDWIDTH_7_MHZ, + { 20250000, 7000000, 0x03291620, 0x01948b10, 0x00ca4bda, 0x00ca4588, 0x00ca3f36, 0x01948b10, 0x00ca4588, 0x006522c4, 0x0288, 0x0195 }, - { 20250000, BANDWIDTH_8_MHZ, + { 20250000, 8000000, 0x039cab92, 0x01ce55c9, 0x00e7321e, 0x00e72ae4, 0x00e723ab, 0x01ce55c9, 0x00e72ae4, 0x00739572, 0x0237, 0x01ce }, - { 20250000, BANDWIDTH_5_MHZ, + { 20250000, 5000000, 0x0241eb3b, 0x0120f59e, 0x00907f53, 0x00907acf, 0x0090764b, 0x0120f59e, 0x00907acf, 0x00483d67, 0x038b, 0x0121 } }; static struct adctable tab4[] = { - { 20583333, BANDWIDTH_6_MHZ, + { 20583333, 6000000, 0x02aa4598, 0x015522cc, 0x00aa96bb, 0x00aa9166, 0x00aa8c12, 0x015522cc, 0x00aa9166, 0x005548b3, 0x0300, 0x0155 }, - { 20583333, BANDWIDTH_7_MHZ, + { 20583333, 7000000, 0x031bfbdc, 0x018dfdee, 0x00c7052f, 0x00c6fef7, 0x00c6f8bf, 0x018dfdee, 0x00c6fef7, 0x00637f7b, 0x0293, 0x018e }, - { 20583333, BANDWIDTH_8_MHZ, + { 20583333, 8000000, 0x038db21f, 0x01c6d910, 0x00e373a3, 0x00e36c88, 0x00e3656d, 0x01c6d910, 0x00e36c88, 0x0071b644, 0x0240, 0x01c7 }, - { 20583333, BANDWIDTH_5_MHZ, + { 20583333, 5000000, 0x02388f54, 0x011c47aa, 0x008e2846, 0x008e23d5, 0x008e1f64, 0x011c47aa, 0x008e23d5, 0x004711ea, 0x039a, 0x011c } }; static struct adctable tab5[] = { - { 20416667, BANDWIDTH_6_MHZ, + { 20416667, 6000000, 0x02afd765, 0x0157ebb3, 0x00abfb39, 0x00abf5d9, 0x00abf07a, 0x0157ebb3, 0x00abf5d9, 0x0055faed, 0x02fa, 0x0158 }, - { 20416667, BANDWIDTH_7_MHZ, + { 20416667, 7000000, 0x03227b4b, 0x01913da6, 0x00c8a518, 0x00c89ed3, 0x00c8988e, 0x01913da6, 0x00c89ed3, 0x00644f69, 0x028d, 0x0191 }, - { 20416667, BANDWIDTH_8_MHZ, + { 20416667, 8000000, 0x03951f32, 0x01ca8f99, 0x00e54ef7, 0x00e547cc, 0x00e540a2, 0x01ca8f99, 0x00e547cc, 0x0072a3e6, 0x023c, 0x01cb }, - { 20416667, BANDWIDTH_5_MHZ, + { 20416667, 5000000, 0x023d337f, 0x011e99c0, 0x008f515a, 0x008f4ce0, 0x008f4865, 0x011e99c0, 0x008f4ce0, 0x0047a670, 0x0393, 0x011f } }; static struct adctable tab6[] = { - { 20480000, BANDWIDTH_6_MHZ, + { 20480000, 6000000, 0x02adb6db, 0x0156db6e, 0x00ab7312, 0x00ab6db7, 0x00ab685c, 0x0156db6e, 0x00ab6db7, 0x0055b6db, 0x02fd, 0x0157 }, - { 20480000, BANDWIDTH_7_MHZ, + { 20480000, 7000000, 0x03200000, 0x01900000, 0x00c80640, 0x00c80000, 0x00c7f9c0, 0x01900000, 0x00c80000, 0x00640000, 0x028f, 0x0190 }, - { 20480000, BANDWIDTH_8_MHZ, + { 20480000, 8000000, 0x03924925, 0x01c92492, 0x00e4996e, 0x00e49249, 0x00e48b25, 0x01c92492, 0x00e49249, 0x00724925, 0x023d, 0x01c9 }, - { 20480000, BANDWIDTH_5_MHZ, + { 20480000, 5000000, 0x023b6db7, 0x011db6db, 0x008edfe5, 0x008edb6e, 0x008ed6f7, 0x011db6db, 0x008edb6e, 0x00476db7, 0x0396, 0x011e } }; static struct adctable tab7[] = { - { 20500000, BANDWIDTH_6_MHZ, + { 20500000, 6000000, 0x02ad0b99, 0x015685cc, 0x00ab4840, 0x00ab42e6, 0x00ab3d8c, 0x015685cc, 0x00ab42e6, 0x0055a173, 0x02fd, 0x0157 }, - { 20500000, BANDWIDTH_7_MHZ, + { 20500000, 7000000, 0x031f3832, 0x018f9c19, 0x00c7d44b, 0x00c7ce0c, 0x00c7c7ce, 0x018f9c19, 0x00c7ce0c, 0x0063e706, 0x0290, 0x0190 }, - { 20500000, BANDWIDTH_8_MHZ, + { 20500000, 8000000, 0x039164cb, 0x01c8b266, 0x00e46056, 0x00e45933, 0x00e45210, 0x01c8b266, 0x00e45933, 0x00722c99, 0x023e, 0x01c9 }, - { 20500000, BANDWIDTH_5_MHZ, + { 20500000, 5000000, 0x023adeff, 0x011d6f80, 0x008ebc36, 0x008eb7c0, 0x008eb34a, 0x011d6f80, 0x008eb7c0, 0x00475be0, 0x0396, 0x011d } }; static struct adctable tab8[] = { - { 20625000, BANDWIDTH_6_MHZ, + { 20625000, 6000000, 0x02a8e4bd, 0x0154725e, 0x00aa3e81, 0x00aa392f, 0x00aa33de, 0x0154725e, 0x00aa392f, 0x00551c98, 0x0302, 0x0154 }, - { 20625000, BANDWIDTH_7_MHZ, + { 20625000, 7000000, 0x031a6032, 0x018d3019, 0x00c69e41, 0x00c6980c, 0x00c691d8, 0x018d3019, 0x00c6980c, 0x00634c06, 0x0294, 0x018d }, - { 20625000, BANDWIDTH_8_MHZ, + { 20625000, 8000000, 0x038bdba6, 0x01c5edd3, 0x00e2fe02, 0x00e2f6ea, 0x00e2efd2, 0x01c5edd3, 0x00e2f6ea, 0x00717b75, 0x0242, 0x01c6 }, - { 20625000, BANDWIDTH_5_MHZ, + { 20625000, 5000000, 0x02376948, 0x011bb4a4, 0x008ddec1, 0x008dda52, 0x008dd5e3, 0x011bb4a4, 0x008dda52, 0x0046ed29, 0x039c, 0x011c } @@ -153,8 +153,7 @@ struct table { }; static struct table fe_clockTable[] = { - {12000000, tab3}, /* FPGA */ - {16384000, tab6}, /* 16.38MHz */ + {12000000, tab3}, /* 12.00MHz */ {20480000, tab6}, /* 20.48MHz */ {36000000, tab3}, /* 36.00MHz */ {30000000, tab1}, /* 30.00MHz */ @@ -164,7 +163,6 @@ static struct table fe_clockTable[] = { {34000000, tab2}, /* 34.00MHz */ {24000000, tab1}, /* 24.00MHz */ {22000000, tab8}, /* 22.00MHz */ - {12000000, tab3} /* 12.00MHz */ }; /* fe get */ @@ -205,6 +203,10 @@ fe_modulation_t fe_con[] = { /* Standard demodulator functions */ static struct it913xset set_solo_fe[] = { + {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, + {PRO_LINK, GPIOH5_ON, {0x01}, 0x01}, + {PRO_LINK, GPIOH5_O, {0x00}, 0x01}, + {PRO_LINK, GPIOH5_O, {0x01}, 0x01}, {PRO_LINK, DVBT_INTEN, {0x04}, 0x01}, {PRO_LINK, DVBT_ENABLE, {0x05}, 0x01}, {PRO_DMOD, MP2IF_MPEG_PAR_MODE, {0x00}, 0x01}, @@ -228,13 +230,127 @@ static struct it913xset init_1[] = { {PRO_LINK, LOCK3_OUT, {0x01}, 0x01}, {PRO_LINK, PADMISCDRSR, {0x01}, 0x01}, {PRO_LINK, PADMISCDR2, {0x00}, 0x01}, + {PRO_DMOD, 0xec57, {0x00, 0x00}, 0x02}, {PRO_LINK, PADMISCDR4, {0x00}, 0x01}, /* Power up */ {PRO_LINK, PADMISCDR8, {0x00}, 0x01}, {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ }; -/* ---------IT9137 0x38 tuner init---------- */ -static struct it913xset it9137_set[] = { + +/* Version 1 types */ +static struct it913xset it9135_v1[] = { + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a}, 0x01}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a}, 0x01}, + {PRO_DMOD, 0x008a, {0x01}, 0x01}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06}, 0x01}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009f, {0xe1}, 0x01}, + {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, + {PRO_DMOD, 0x00a3, {0x01}, 0x01}, + {PRO_DMOD, 0x00a5, {0x01}, 0x01}, + {PRO_DMOD, 0x00a6, {0x01}, 0x01}, + {PRO_DMOD, 0x00a9, {0x00}, 0x01}, + {PRO_DMOD, 0x00aa, {0x01}, 0x01}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00c2, {0x05}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10}, 0x01}, + {PRO_DMOD, 0xf017, {0x04}, 0x01}, + {PRO_DMOD, 0xf018, {0x05}, 0x01}, + {PRO_DMOD, 0xf019, {0x04}, 0x01}, + {PRO_DMOD, 0xf01a, {0x05}, 0x01}, + {PRO_DMOD, 0xf021, {0x03}, 0x01}, + {PRO_DMOD, 0xf022, {0x0a}, 0x01}, + {PRO_DMOD, 0xf023, {0x0a}, 0x01}, + {PRO_DMOD, 0xf02b, {0x00}, 0x01}, + {PRO_DMOD, 0xf02c, {0x01}, 0x01}, + {PRO_DMOD, 0xf064, {0x03}, 0x01}, + {PRO_DMOD, 0xf065, {0xf9}, 0x01}, + {PRO_DMOD, 0xf066, {0x03}, 0x01}, + {PRO_DMOD, 0xf067, {0x01}, 0x01}, + {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, + {PRO_DMOD, 0xf070, {0x03}, 0x01}, + {PRO_DMOD, 0xf072, {0x0f}, 0x01}, + {PRO_DMOD, 0xf073, {0x03}, 0x01}, + {PRO_DMOD, 0xf078, {0x00}, 0x01}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, + {PRO_DMOD, 0xf09c, {0x00}, 0x01}, + {PRO_DMOD, 0xf09d, {0x20}, 0x01}, + {PRO_DMOD, 0xf09e, {0x00}, 0x01}, + {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, + {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00}, 0x01}, + {PRO_DMOD, 0xf14d, {0x00}, 0x01}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00}, 0x01}, + {PRO_DMOD, 0xf15b, {0x08}, 0x01}, + {PRO_DMOD, 0xf15d, {0x03}, 0x01}, + {PRO_DMOD, 0xf15e, {0x05}, 0x01}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01}, 0x01}, + {PRO_DMOD, 0xf167, {0x40}, 0x01}, + {PRO_DMOD, 0xf168, {0x0f}, 0x01}, + {PRO_DMOD, 0xf17a, {0x00}, 0x01}, + {PRO_DMOD, 0xf17b, {0x00}, 0x01}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, + {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, + {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, + {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, + {PRO_DMOD, 0xf40f, {0x40}, 0x01}, + {PRO_DMOD, 0xf410, {0x08}, 0x01}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15}, 0x01}, + {PRO_DMOD, 0xf562, {0x20}, 0x01}, + {PRO_DMOD, 0xf5df, {0xfb}, 0x01}, + {PRO_DMOD, 0xf5e0, {0x00}, 0x01}, + {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, + {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, + {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05}, 0x01}, + {PRO_DMOD, 0xf601, {0x08}, 0x01}, + {PRO_DMOD, 0xf602, {0x0b}, 0x01}, + {PRO_DMOD, 0xf603, {0x0e}, 0x01}, + {PRO_DMOD, 0xf604, {0x11}, 0x01}, + {PRO_DMOD, 0xf605, {0x14}, 0x01}, + {PRO_DMOD, 0xf606, {0x17}, 0x01}, + {PRO_DMOD, 0xf607, {0x1f}, 0x01}, + {PRO_DMOD, 0xf60e, {0x00}, 0x01}, + {PRO_DMOD, 0xf60f, {0x04}, 0x01}, + {PRO_DMOD, 0xf610, {0x32}, 0x01}, + {PRO_DMOD, 0xf611, {0x10}, 0x01}, + {PRO_DMOD, 0xf707, {0xfc}, 0x01}, + {PRO_DMOD, 0xf708, {0x00}, 0x01}, + {PRO_DMOD, 0xf709, {0x37}, 0x01}, + {PRO_DMOD, 0xf70a, {0x00}, 0x01}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40}, 0x01}, + {PRO_DMOD, 0xf810, {0x54}, 0x01}, + {PRO_DMOD, 0xf811, {0x5a}, 0x01}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_38[] = { {PRO_DMOD, 0x0043, {0x00}, 0x01}, {PRO_DMOD, 0x0046, {0x38}, 0x01}, {PRO_DMOD, 0x0051, {0x01}, 0x01}, @@ -244,7 +360,7 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8, - 0xd0, 0xc3, 0x01 }, 0x0a}, + 0xd0, 0xc3, 0x01}, 0x0a}, {PRO_DMOD, 0x008e, {0x01}, 0x01}, {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, {PRO_DMOD, 0x0099, {0x01}, 0x01}, @@ -262,15 +378,25 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, {PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77, - 0x00, 0x02, 0xc8, 0x05, 0x7b }, 0x0c}, + 0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c}, {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, - {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0xbc, 0xa0}, 0x04}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04}, {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03}, {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, - {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8}, 0x04}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, {PRO_DMOD, 0xf130, {0x04}, 0x01}, {PRO_DMOD, 0xf132, {0x04}, 0x01}, {PRO_DMOD, 0xf144, {0x1a}, 0x01}, @@ -301,7 +427,7 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f }, 0x08}, + 0x1f}, 0x08}, {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, {PRO_DMOD, 0xf78b, {0x01}, 0x01}, @@ -309,21 +435,605 @@ static struct it913xset it9137_set[] = { {PRO_DMOD, 0xf905, {0x01}, 0x01}, {PRO_DMOD, 0xfb06, {0x03}, 0x01}, {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {PRO_LINK, GPIOH5_EN, {0x01}, 0x01}, - {PRO_LINK, GPIOH5_ON, {0x01}, 0x01}, - {PRO_LINK, GPIOH5_O, {0x00}, 0x01}, - {PRO_LINK, GPIOH5_O, {0x01}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_51[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x51}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96, + 0xcf, 0xc3, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77, + 0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04}, + {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_52[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x52}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x10}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97, + 0xc0, 0x9e, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77, + 0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04}, + {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ }; +/* Version 2 types */ +static struct it913xset it9135_v2[] = { + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a}, 0x01}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a}, 0x01}, + {PRO_DMOD, 0x008a, {0x01}, 0x01}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06}, 0x01}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009f, {0xe1}, 0x01}, + {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, + {PRO_DMOD, 0x00a3, {0x01}, 0x01}, + {PRO_DMOD, 0x00a5, {0x01}, 0x01}, + {PRO_DMOD, 0x00a6, {0x01}, 0x01}, + {PRO_DMOD, 0x00a9, {0x00}, 0x01}, + {PRO_DMOD, 0x00aa, {0x01}, 0x01}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00c2, {0x05}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf02b, {0x00}, 0x01}, + {PRO_DMOD, 0xf064, {0x03}, 0x01}, + {PRO_DMOD, 0xf065, {0xf9}, 0x01}, + {PRO_DMOD, 0xf066, {0x03}, 0x01}, + {PRO_DMOD, 0xf067, {0x01}, 0x01}, + {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, + {PRO_DMOD, 0xf070, {0x03}, 0x01}, + {PRO_DMOD, 0xf072, {0x0f}, 0x01}, + {PRO_DMOD, 0xf073, {0x03}, 0x01}, + {PRO_DMOD, 0xf078, {0x00}, 0x01}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, + {PRO_DMOD, 0xf09c, {0x00}, 0x01}, + {PRO_DMOD, 0xf09d, {0x20}, 0x01}, + {PRO_DMOD, 0xf09e, {0x00}, 0x01}, + {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, + {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00}, 0x01}, + {PRO_DMOD, 0xf14d, {0x00}, 0x01}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00}, 0x01}, + {PRO_DMOD, 0xf15b, {0x08}, 0x01}, + {PRO_DMOD, 0xf15d, {0x03}, 0x01}, + {PRO_DMOD, 0xf15e, {0x05}, 0x01}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01}, 0x01}, + {PRO_DMOD, 0xf167, {0x40}, 0x01}, + {PRO_DMOD, 0xf168, {0x0f}, 0x01}, + {PRO_DMOD, 0xf17a, {0x00}, 0x01}, + {PRO_DMOD, 0xf17b, {0x00}, 0x01}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, + {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, + {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, + {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, + {PRO_DMOD, 0xf40f, {0x40}, 0x01}, + {PRO_DMOD, 0xf410, {0x08}, 0x01}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15}, 0x01}, + {PRO_DMOD, 0xf562, {0x20}, 0x01}, + {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, + {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, + {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05}, 0x01}, + {PRO_DMOD, 0xf601, {0x08}, 0x01}, + {PRO_DMOD, 0xf602, {0x0b}, 0x01}, + {PRO_DMOD, 0xf603, {0x0e}, 0x01}, + {PRO_DMOD, 0xf604, {0x11}, 0x01}, + {PRO_DMOD, 0xf605, {0x14}, 0x01}, + {PRO_DMOD, 0xf606, {0x17}, 0x01}, + {PRO_DMOD, 0xf607, {0x1f}, 0x01}, + {PRO_DMOD, 0xf60e, {0x00}, 0x01}, + {PRO_DMOD, 0xf60f, {0x04}, 0x01}, + {PRO_DMOD, 0xf610, {0x32}, 0x01}, + {PRO_DMOD, 0xf611, {0x10}, 0x01}, + {PRO_DMOD, 0xf707, {0xfc}, 0x01}, + {PRO_DMOD, 0xf708, {0x00}, 0x01}, + {PRO_DMOD, 0xf709, {0x37}, 0x01}, + {PRO_DMOD, 0xf70a, {0x00}, 0x01}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40}, 0x01}, + {PRO_DMOD, 0xf810, {0x54}, 0x01}, + {PRO_DMOD, 0xf811, {0x5a}, 0x01}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_60[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x60}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c, + 0x00, 0x02, 0xbe, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xbe}, 0x01}, + {PRO_DMOD, 0x0124, {0xae}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x08}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c, + 0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xbc}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02}, + {PRO_DMOD, 0x0185, {0x24}, 0x01}, + {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17 + , 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_61[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x61}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x06}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c, + 0x01, 0x02, 0xc8, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xc6}, 0x01}, + {PRO_DMOD, 0x0124, {0xa8}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x05}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c, + 0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xcc}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02}, + {PRO_DMOD, 0x0185, {0x28}, 0x01}, + {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_62[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x62}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, { 0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01}, + 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c, + 0x02, 0x02, 0xc2, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xb8}, 0x01}, + {PRO_DMOD, 0x0124, {0xa8}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x05}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c, + 0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xb2}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02}, + {PRO_DMOD, 0x0185, {0x24}, 0x01}, + {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +/* Tuner setting scripts (still keeping it9137) */ static struct it913xset it9137_tuner_off[] = { {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, + {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, 0x0c}, + {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, + {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}, 0x09}, + {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}, 0x0a}, + {PRO_DMOD, 0xec20, {0x00}, 0x01}, {PRO_DMOD, 0xec3f, {0x01}, 0x01}, {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ }; +static struct it913xset set_it9135_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */ + {PRO_DMOD, 0x011f, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + static struct it913xset set_it9137_template[] = { {PRO_DMOD, 0xee06, {0x00}, 0x01}, {PRO_DMOD, 0xec56, {0x00}, 0x01}, diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c index d4bd24eb4700..ccc36bf2deb4 100644 --- a/drivers/media/dvb/frontends/it913x-fe.c +++ b/drivers/media/dvb/frontends/it913x-fe.c @@ -46,13 +46,17 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); dprintk(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \ *p, *(p+1), *(p+2), *(p+3), *(p+4), \ *(p+5), *(p+6), *(p+7)); +#define info(format, arg...) \ + printk(KERN_INFO "it913x-fe: " format "\n" , ## arg) struct it913x_fe_state { struct dvb_frontend frontend; struct i2c_adapter *i2c_adap; + struct ite_config *config; u8 i2c_addr; u32 frequency; - u8 adf; + fe_modulation_t constellation; + fe_transmit_mode_t transmission_mode; u32 crystalFrequency; u32 adcFrequency; u8 tuner_type; @@ -62,6 +66,7 @@ struct it913x_fe_state { u8 tun_fdiv; u8 tun_clk_mode; u32 tun_fn_min; + u32 ucblocks; }; static int it913x_read_reg(struct it913x_fe_state *state, @@ -211,20 +216,24 @@ static int it913x_init_tuner(struct it913x_fe_state *state) state->tun_fn_min /= (state->tun_fdiv * nv_val); deb_info("Tuner fn_min %d", state->tun_fn_min); - for (i = 0; i < 50; i++) { - reg = it913x_read_reg_u8(state, 0xec82); - if (reg > 0) - break; - if (reg < 0) - return -ENODEV; - udelay(2000); + if (state->config->chip_ver > 1) + msleep(50); + else { + for (i = 0; i < 50; i++) { + reg = it913x_read_reg_u8(state, 0xec82); + if (reg > 0) + break; + if (reg < 0) + return -ENODEV; + udelay(2000); + } } return it913x_write_reg(state, PRO_DMOD, 0xed81, val); } static int it9137_set_tuner(struct it913x_fe_state *state, - enum fe_bandwidth bandwidth, u32 frequency_m) + u32 bandwidth, u32 frequency_m) { struct it913xset *set_tuner = set_it9137_template; int ret, reg; @@ -237,6 +246,11 @@ static int it9137_set_tuner(struct it913x_fe_state *state, u8 lna_band; u8 bw; + if (state->config->firmware_ver == 1) + set_tuner = set_it9135_template; + else + set_tuner = set_it9137_template; + deb_info("Tuner Frequency %d Bandwidth %d", frequency, bandwidth); if (frequency >= 51000 && frequency <= 440000) { @@ -273,16 +287,21 @@ static int it9137_set_tuner(struct it913x_fe_state *state, return -EINVAL; set_tuner[0].reg[0] = lna_band; - if (bandwidth == BANDWIDTH_5_MHZ) + switch (bandwidth) { + case 5000000: bw = 0; - else if (bandwidth == BANDWIDTH_6_MHZ) + break; + case 6000000: bw = 2; - else if (bandwidth == BANDWIDTH_7_MHZ) + break; + case 7000000: bw = 4; - else if (bandwidth == BANDWIDTH_8_MHZ) - bw = 6; - else + break; + default: + case 8000000: bw = 6; + break; + } set_tuner[1].reg[0] = bw; set_tuner[2].reg[0] = 0xa0 | (l_band << 3); @@ -361,7 +380,7 @@ static int it9137_set_tuner(struct it913x_fe_state *state, } static int it913x_fe_select_bw(struct it913x_fe_state *state, - enum fe_bandwidth bandwidth, u32 adcFrequency) + u32 bandwidth, u32 adcFrequency) { int ret, i; u8 buffer[256]; @@ -374,17 +393,21 @@ static int it913x_fe_select_bw(struct it913x_fe_state *state, deb_info("Bandwidth %d Adc %d", bandwidth, adcFrequency); - if (bandwidth == BANDWIDTH_5_MHZ) + switch (bandwidth) { + case 5000000: bw = 3; - else if (bandwidth == BANDWIDTH_6_MHZ) + break; + case 6000000: bw = 0; - else if (bandwidth == BANDWIDTH_7_MHZ) + break; + case 7000000: bw = 1; - else if (bandwidth == BANDWIDTH_8_MHZ) - bw = 2; - else + break; + default: + case 8000000: bw = 2; - + break; + } ret = it913x_write_reg(state, PRO_DMOD, REG_BW, bw); if (state->table == NULL) @@ -492,31 +515,79 @@ static int it913x_fe_read_signal_strength(struct dvb_frontend *fe, return 0; } -static int it913x_fe_read_snr(struct dvb_frontend *fe, u16* snr) +static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr) { struct it913x_fe_state *state = fe->demodulator_priv; - int ret = it913x_read_reg_u8(state, SIGNAL_QUALITY); - ret = (ret * 0xff) / 0x64; - ret |= (ret << 0x8); - *snr = ~ret; - return 0; + int ret; + u8 reg[3]; + u32 snr_val, snr_min, snr_max; + u32 temp; + + ret = it913x_read_reg(state, 0x2c, reg, sizeof(reg)); + + snr_val = (u32)(reg[2] << 16) | (reg[1] << 8) | reg[0]; + + ret |= it913x_read_reg(state, 0xf78b, reg, 1); + if (reg[0]) + snr_val /= reg[0]; + + if (state->transmission_mode == TRANSMISSION_MODE_2K) + snr_val *= 4; + else if (state->transmission_mode == TRANSMISSION_MODE_4K) + snr_val *= 2; + + if (state->constellation == QPSK) { + snr_min = 0xb4711; + snr_max = 0x191451; + } else if (state->constellation == QAM_16) { + snr_min = 0x4f0d5; + snr_max = 0xc7925; + } else if (state->constellation == QAM_64) { + snr_min = 0x256d0; + snr_max = 0x626be; + } else + return -EINVAL; + + if (snr_val < snr_min) + *snr = 0; + else if (snr_val < snr_max) { + temp = (snr_val - snr_min) >> 5; + temp *= 0xffff; + temp /= (snr_max - snr_min) >> 5; + *snr = (u16)temp; + } else + *snr = 0xffff; + + return (ret < 0) ? -ENODEV : 0; } static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber) { - *ber = 0; + struct it913x_fe_state *state = fe->demodulator_priv; + int ret; + u8 reg[5]; + /* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */ + ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); + state->ucblocks += (u32)(reg[1] << 8) | reg[0]; + *ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2]; return 0; } static int it913x_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - *ucblocks = 0; - return 0; + struct it913x_fe_state *state = fe->demodulator_priv; + int ret; + u8 reg[2]; + /* Aborted Packets */ + ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg)); + state->ucblocks += (u32)(reg[1] << 8) | reg[0]; + *ucblocks = state->ucblocks; + return ret; } -static int it913x_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int it913x_fe_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; int ret; u8 reg[8]; @@ -524,26 +595,30 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe, ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg)); if (reg[3] < 3) - p->u.ofdm.constellation = fe_con[reg[3]]; + p->modulation = fe_con[reg[3]]; if (reg[0] < 3) - p->u.ofdm.transmission_mode = fe_mode[reg[0]]; + p->transmission_mode = fe_mode[reg[0]]; if (reg[1] < 4) - p->u.ofdm.guard_interval = fe_gi[reg[1]]; + p->guard_interval = fe_gi[reg[1]]; if (reg[2] < 4) - p->u.ofdm.hierarchy_information = fe_hi[reg[2]]; + p->hierarchy = fe_hi[reg[2]]; + + p->code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; + p->code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; - p->u.ofdm.code_rate_HP = (reg[6] < 6) ? fe_code[reg[6]] : FEC_NONE; - p->u.ofdm.code_rate_LP = (reg[7] < 6) ? fe_code[reg[7]] : FEC_NONE; + /* Update internal state to reflect the autodetected props */ + state->constellation = p->modulation; + state->transmission_mode = p->transmission_mode; return 0; } -static int it913x_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int it913x_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct it913x_fe_state *state = fe->demodulator_priv; int ret, i; u8 empty_ch, last_ch; @@ -551,7 +626,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe, state->it913x_status = 0; /* Set bw*/ - ret = it913x_fe_select_bw(state, p->u.ofdm.bandwidth, + ret = it913x_fe_select_bw(state, p->bandwidth_hz, state->adcFrequency); /* Training Mode Off */ @@ -571,20 +646,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe, i = 1; else if ((p->frequency >= 1450000000) && (p->frequency <= 1680000000)) i = 2; - else - return -EOPNOTSUPP; + else + return -EOPNOTSUPP; ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i); deb_info("Frontend Set Tuner Type %02x", state->tuner_type); switch (state->tuner_type) { - case IT9137: /* Tuner type 0x38 */ + case IT9135_38: + case IT9135_51: + case IT9135_52: + case IT9135_60: + case IT9135_61: + case IT9135_62: ret = it9137_set_tuner(state, - p->u.ofdm.bandwidth, p->frequency); + p->bandwidth_hz, p->frequency); break; default: if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -678,16 +758,19 @@ static u32 compute_div(u32 a, u32 b, u32 x) static int it913x_fe_start(struct it913x_fe_state *state) { - struct it913xset *set_fe; + struct it913xset *set_lna; struct it913xset *set_mode; int ret; - u8 adf = (state->adf & 0xf); + u8 adf = (state->config->adf & 0xf); u32 adc, xtal; u8 b[4]; - ret = it913x_init_tuner(state); + if (state->config->chip_ver == 1) + ret = it913x_init_tuner(state); + + info("ADF table value :%02x", adf); - if (adf < 12) { + if (adf < 10) { state->crystalFrequency = fe_clockTable[adf].xtal ; state->table = fe_clockTable[adf].table; state->adcFrequency = state->table->adcFrequency; @@ -698,9 +781,6 @@ static int it913x_fe_start(struct it913x_fe_state *state) } else return -EINVAL; - deb_info("Xtal Freq :%d Adc Freq :%d Adc %08x Xtal %08x", - state->crystalFrequency, state->adcFrequency, adc, xtal); - /* Set LED indicator on GPIOH3 */ ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1); ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1); @@ -721,22 +801,71 @@ static int it913x_fe_start(struct it913x_fe_state *state) b[2] = (adc >> 16) & 0xff; ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3); + if (state->config->adc_x2) + ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01); + b[0] = 0; + b[1] = 0; + b[2] = 0; + ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3); + + info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x", + state->crystalFrequency, state->adcFrequency, + state->config->adc_x2); + deb_info("Xtal value :%04x Adc value :%04x", xtal, adc); + + if (ret < 0) + return -ENODEV; + + /* v1 or v2 tuner script */ + if (state->config->chip_ver > 1) + ret = it913x_fe_script_loader(state, it9135_v2); + else + ret = it913x_fe_script_loader(state, it9135_v1); + if (ret < 0) + return ret; + + /* LNA Scripts */ switch (state->tuner_type) { - case IT9137: /* Tuner type 0x38 */ - set_fe = it9137_set; + case IT9135_51: + set_lna = it9135_51; + break; + case IT9135_52: + set_lna = it9135_52; + break; + case IT9135_60: + set_lna = it9135_60; + break; + case IT9135_61: + set_lna = it9135_61; break; + case IT9135_62: + set_lna = it9135_62; + break; + case IT9135_38: default: - return -EINVAL; + set_lna = it9135_38; } + info("Tuner LNA type :%02x", state->tuner_type); + + ret = it913x_fe_script_loader(state, set_lna); + if (ret < 0) + return ret; + + if (state->config->chip_ver == 2) { + ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0); + ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0); + ret |= it913x_init_tuner(state); + } + if (ret < 0) + return -ENODEV; - /* set the demod */ - ret = it913x_fe_script_loader(state, set_fe); /* Always solo frontend */ set_mode = set_solo_fe; ret |= it913x_fe_script_loader(state, set_mode); ret |= it913x_fe_suspend(state); - return 0; + return (ret < 0) ? -ENODEV : 0; } static int it913x_fe_init(struct dvb_frontend *fe) @@ -746,17 +875,11 @@ static int it913x_fe_init(struct dvb_frontend *fe) /* Power Up Tuner - common all versions */ ret = it913x_write_reg(state, PRO_DMOD, 0xec40, 0x1); - ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); - ret |= it913x_fe_script_loader(state, init_1); - switch (state->tuner_type) { - case IT9137: - ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0); - break; - default: - return -EINVAL; - } + ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x0); + + ret |= it913x_write_reg(state, PRO_DMOD, 0xfba8, 0x0); return (ret < 0) ? -ENODEV : 0; } @@ -770,19 +893,34 @@ static void it913x_fe_release(struct dvb_frontend *fe) static struct dvb_frontend_ops it913x_fe_ofdm_ops; struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, u8 adf, u8 type) + u8 i2c_addr, struct ite_config *config) { struct it913x_fe_state *state = NULL; int ret; + /* allocate memory for the internal state */ state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL); if (state == NULL) + return NULL; + if (config == NULL) goto error; state->i2c_adap = i2c_adap; state->i2c_addr = i2c_addr; - state->adf = adf; - state->tuner_type = type; + state->config = config; + + switch (state->config->tuner_id_0) { + case IT9135_51: + case IT9135_52: + case IT9135_60: + case IT9135_61: + case IT9135_62: + state->tuner_type = state->config->tuner_id_0; + break; + default: + case IT9135_38: + state->tuner_type = IT9135_38; + } ret = it913x_fe_start(state); if (ret < 0) @@ -802,10 +940,9 @@ error: EXPORT_SYMBOL(it913x_fe_attach); static struct dvb_frontend_ops it913x_fe_ofdm_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "it913x-fe DVB-T", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 1680000000, .frequency_stepsize = 62500, @@ -835,5 +972,5 @@ static struct dvb_frontend_ops it913x_fe_ofdm_ops = { MODULE_DESCRIPTION("it913x Frontend and it9137 tuner"); MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); -MODULE_VERSION("1.07"); +MODULE_VERSION("1.13"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/it913x-fe.h b/drivers/media/dvb/frontends/it913x-fe.h index 9d97f32e690b..c4a908e354e0 100644 --- a/drivers/media/dvb/frontends/it913x-fe.h +++ b/drivers/media/dvb/frontends/it913x-fe.h @@ -23,13 +23,27 @@ #include <linux/dvb/frontend.h> #include "dvb_frontend.h" + +struct ite_config { + u8 chip_ver; + u16 chip_type; + u32 firmware; + u8 firmware_ver; + u8 adc_x2; + u8 tuner_id_0; + u8 tuner_id_1; + u8 dual_mode; + u8 adf; +}; + #if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ defined(MODULE)) extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, u8 adf, u8 type); + u8 i2c_addr, struct ite_config *config); #else static inline struct dvb_frontend *it913x_fe_attach( - struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 adf, u8 type) + struct i2c_adapter *i2c_adap, + u8 i2c_addr, struct ite_config *config) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; @@ -134,6 +148,16 @@ static inline struct dvb_frontend *it913x_fe_attach( #define COEFF_1_2048 0x0001 #define XTAL_CLK 0x0025 #define BFS_FCW 0x0029 + +/* Error Regs */ +#define RSD_ABORT_PKT_LSB 0x0032 +#define RSD_ABORT_PKT_MSB 0x0033 +#define RSD_BIT_ERR_0_7 0x0034 +#define RSD_BIT_ERR_8_15 0x0035 +#define RSD_BIT_ERR_23_16 0x0036 +#define RSD_BIT_COUNT_LSB 0x0037 +#define RSD_BIT_COUNT_MSB 0x0038 + #define TPSD_LOCK 0x003c #define TRAINING_MODE 0x0040 #define ADC_X_2 0x0045 @@ -144,8 +168,14 @@ static inline struct dvb_frontend *it913x_fe_attach( #define EST_SIGNAL_LEVEL 0x004a #define FREE_BAND 0x004b #define SUSPEND_FLAG 0x004c -/* Build in tuners */ +/* Build in tuner types */ #define IT9137 0x38 +#define IT9135_38 0x38 +#define IT9135_51 0x51 +#define IT9135_52 0x52 +#define IT9135_60 0x60 +#define IT9135_61 0x61 +#define IT9135_62 0x62 enum { CMD_DEMOD_READ = 0, @@ -193,4 +223,11 @@ enum { WRITE_CMD, }; +enum { + IT9135_AUTO = 0, + IT9137_FW, + IT9135_V1_FW, + IT9135_V2_FW, +}; + #endif /* IT913X_FE_H */ diff --git a/drivers/media/dvb/frontends/itd1000.c b/drivers/media/dvb/frontends/itd1000.c index aa9ccb821fa5..316457584fe7 100644 --- a/drivers/media/dvb/frontends/itd1000.c +++ b/drivers/media/dvb/frontends/itd1000.c @@ -250,13 +250,14 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) itd1000_set_vco(state, freq_khz); } -static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int itd1000_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct itd1000_state *state = fe->tuner_priv; u8 pllcon1; - itd1000_set_lo(state, p->frequency); - itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate); + itd1000_set_lo(state, c->frequency); + itd1000_set_lpf_bw(state, c->symbol_rate); pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f; itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7)); diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c index 9a517a4bf96d..bc5a82082aaa 100644 --- a/drivers/media/dvb/frontends/ix2505v.c +++ b/drivers/media/dvb/frontends/ix2505v.c @@ -129,12 +129,12 @@ static int ix2505v_release(struct dvb_frontend *fe) * 1 -> 8 -> 6 */ -static int ix2505v_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int ix2505v_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct ix2505v_state *state = fe->tuner_priv; - u32 frequency = params->frequency; - u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + u32 frequency = c->frequency; + u32 b_w = (c->symbol_rate * 27) / 32000; u32 div_factor, N , A, x; int ret = 0, len; u8 gain, cc, ref, psc, local_osc, lpf; diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 445fa1068064..36fcf559e361 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -117,18 +117,17 @@ static int reset_and_configure (struct l64781_state* state) return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; } -static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +static int apply_frontend_param(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct l64781_state* state = fe->demodulator_priv; /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; /* QPSK, QAM_16, QAM_64 */ static const u8 qam_tab [] = { 2, 4, 0, 6 }; - static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ static const u8 guard_tab [] = { 1, 2, 4, 8 }; /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ static const u32 ppm = 8000; - struct dvb_ofdm_parameters *p = ¶m->u.ofdm; u32 ddfs_offset_fixed; /* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ /* bw_tab[p->bandWidth]<<10)/15625; */ @@ -137,18 +136,29 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa u8 val0x04; u8 val0x05; u8 val0x06; - int bw = p->bandwidth - BANDWIDTH_8_MHZ; + int bw; + + switch (p->bandwidth_hz) { + case 8000000: + bw = 8; + break; + case 7000000: + bw = 7; + break; + case 6000000: + bw = 6; + break; + default: + return -EINVAL; + } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - if (param->inversion != INVERSION_ON && - param->inversion != INVERSION_OFF) - return -EINVAL; - - if (bw < 0 || bw > 2) + if (p->inversion != INVERSION_ON && + p->inversion != INVERSION_OFF) return -EINVAL; if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && @@ -156,14 +166,14 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa p->code_rate_HP != FEC_7_8) return -EINVAL; - if (p->hierarchy_information != HIERARCHY_NONE && + if (p->hierarchy != HIERARCHY_NONE && (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && p->code_rate_LP != FEC_7_8)) return -EINVAL; - if (p->constellation != QPSK && p->constellation != QAM_16 && - p->constellation != QAM_64) + if (p->modulation != QPSK && p->modulation != QAM_16 && + p->modulation != QAM_64) return -EINVAL; if (p->transmission_mode != TRANSMISSION_MODE_2K && @@ -174,22 +184,22 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa p->guard_interval > GUARD_INTERVAL_1_4) return -EINVAL; - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) + if (p->hierarchy < HIERARCHY_NONE || + p->hierarchy > HIERARCHY_4) return -EINVAL; - ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; + ddfs_offset_fixed = 0x4000-(ppm<<16)/bw/1000000; /* This works up to 20000 ppm, it overflows if too large ppm! */ init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / - bw_tab[p->bandwidth] & 0xFFFFFF); + bw & 0xFFFFFF); /* SPI bias calculation is slightly modified to fit in 32bit */ /* will work for high ppm only... */ spi_bias = 378 * (1 << 10); spi_bias *= 16; - spi_bias *= bw_tab[p->bandwidth]; - spi_bias *= qam_tab[p->constellation]; + spi_bias *= bw; + spi_bias *= qam_tab[p->modulation]; spi_bias /= p->code_rate_HP + 1; spi_bias /= (guard_tab[p->guard_interval] + 32); spi_bias *= 1000; @@ -199,10 +209,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa val0x04 = (p->transmission_mode << 2) | p->guard_interval; val0x05 = fec_tab[p->code_rate_HP]; - if (p->hierarchy_information != HIERARCHY_NONE) + if (p->hierarchy != HIERARCHY_NONE) val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; - val0x06 = (p->hierarchy_information << 2) | p->constellation; + val0x06 = (p->hierarchy << 2) | p->modulation; l64781_writereg (state, 0x04, val0x04); l64781_writereg (state, 0x05, val0x05); @@ -220,7 +230,7 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa l64781_writereg (state, 0x1b, spi_bias & 0xff); l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | - (param->inversion == INVERSION_ON ? 0x80 : 0x00)); + (p->inversion == INVERSION_ON ? 0x80 : 0x00)); l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); @@ -233,8 +243,9 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa return 0; } -static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) +static int get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct l64781_state* state = fe->demodulator_priv; int tmp; @@ -242,98 +253,95 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* tmp = l64781_readreg(state, 0x04); switch(tmp & 3) { case 0: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + p->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + p->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + p->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + p->guard_interval = GUARD_INTERVAL_1_4; break; } switch((tmp >> 2) & 3) { case 0: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + p->transmission_mode = TRANSMISSION_MODE_2K; break; case 1: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + p->transmission_mode = TRANSMISSION_MODE_8K; break; default: - printk("Unexpected value for transmission_mode\n"); + printk(KERN_WARNING "Unexpected value for transmission_mode\n"); } - - tmp = l64781_readreg(state, 0x05); switch(tmp & 7) { case 0: - param->u.ofdm.code_rate_HP = FEC_1_2; + p->code_rate_HP = FEC_1_2; break; case 1: - param->u.ofdm.code_rate_HP = FEC_2_3; + p->code_rate_HP = FEC_2_3; break; case 2: - param->u.ofdm.code_rate_HP = FEC_3_4; + p->code_rate_HP = FEC_3_4; break; case 3: - param->u.ofdm.code_rate_HP = FEC_5_6; + p->code_rate_HP = FEC_5_6; break; case 4: - param->u.ofdm.code_rate_HP = FEC_7_8; + p->code_rate_HP = FEC_7_8; break; default: printk("Unexpected value for code_rate_HP\n"); } switch((tmp >> 3) & 7) { case 0: - param->u.ofdm.code_rate_LP = FEC_1_2; + p->code_rate_LP = FEC_1_2; break; case 1: - param->u.ofdm.code_rate_LP = FEC_2_3; + p->code_rate_LP = FEC_2_3; break; case 2: - param->u.ofdm.code_rate_LP = FEC_3_4; + p->code_rate_LP = FEC_3_4; break; case 3: - param->u.ofdm.code_rate_LP = FEC_5_6; + p->code_rate_LP = FEC_5_6; break; case 4: - param->u.ofdm.code_rate_LP = FEC_7_8; + p->code_rate_LP = FEC_7_8; break; default: printk("Unexpected value for code_rate_LP\n"); } - tmp = l64781_readreg(state, 0x06); switch(tmp & 3) { case 0: - param->u.ofdm.constellation = QPSK; + p->modulation = QPSK; break; case 1: - param->u.ofdm.constellation = QAM_16; + p->modulation = QAM_16; break; case 2: - param->u.ofdm.constellation = QAM_64; + p->modulation = QAM_64; break; default: - printk("Unexpected value for constellation\n"); + printk(KERN_WARNING "Unexpected value for modulation\n"); } switch((tmp >> 2) & 7) { case 0: - param->u.ofdm.hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - param->u.ofdm.hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - param->u.ofdm.hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - param->u.ofdm.hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; default: printk("Unexpected value for hierarchy\n"); @@ -341,12 +349,12 @@ static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* tmp = l64781_readreg (state, 0x1d); - param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; + p->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; tmp = (int) (l64781_readreg (state, 0x08) | (l64781_readreg (state, 0x09) << 8) | (l64781_readreg (state, 0x0a) << 16)); - param->frequency += tmp; + p->frequency += tmp; return 0; } @@ -564,10 +572,9 @@ error: } static struct dvb_frontend_ops l64781_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "LSI L64781 DVB-T", - .type = FE_OFDM, /* .frequency_min = ???,*/ /* .frequency_max = ???,*/ .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c index 3272881cb112..1d2c47378cf8 100644 --- a/drivers/media/dvb/frontends/lgdt3305.c +++ b/drivers/media/dvb/frontends/lgdt3305.c @@ -266,7 +266,7 @@ fail: } static int lgdt3305_set_modulation(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u8 opermode; int ret; @@ -279,7 +279,7 @@ static int lgdt3305_set_modulation(struct lgdt3305_state *state, opermode &= ~0x03; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: opermode |= 0x03; break; @@ -298,11 +298,11 @@ fail: } static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { int val; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: val = 0; break; @@ -321,11 +321,11 @@ static int lgdt3305_set_filter_extension(struct lgdt3305_state *state, /* ------------------------------------------------------------------------ */ static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 agc_ref; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: agc_ref = 0x32c4; break; @@ -348,11 +348,11 @@ static int lgdt3305_passband_digital_agc(struct lgdt3305_state *state, } static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 ifbw, rfbw, agcdelay; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: agcdelay = 0x04c0; rfbw = 0x8000; @@ -398,11 +398,11 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state, } static int lgdt3305_agc_setup(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { int lockdten, acqen; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: lockdten = 0; acqen = 0; @@ -432,15 +432,15 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state, return -EINVAL; } - return lgdt3305_rfagc_loop(state, param); + return lgdt3305_rfagc_loop(state, p); } static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 usref = 0; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: if (state->cfg->usref_8vsb) usref = state->cfg->usref_8vsb; @@ -473,14 +473,14 @@ static int lgdt3305_set_agc_power_ref(struct lgdt3305_state *state, /* ------------------------------------------------------------------------ */ static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param, + struct dtv_frontend_properties *p, int inversion) { int ret; lg_dbg("(%d)\n", inversion); - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: ret = lgdt3305_write_reg(state, LGDT3305_CR_CTRL_7, inversion ? 0xf9 : 0x79); @@ -497,13 +497,13 @@ static int lgdt3305_spectral_inversion(struct lgdt3305_state *state, } static int lgdt3305_set_if(struct lgdt3305_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { u16 if_freq_khz; u8 nco1, nco2, nco3, nco4; u64 nco; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: if_freq_khz = state->cfg->vsb_if_khz; break; @@ -517,7 +517,7 @@ static int lgdt3305_set_if(struct lgdt3305_state *state, nco = if_freq_khz / 10; - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: nco <<= 24; do_div(nco, 625); @@ -677,37 +677,37 @@ fail: return ret; } -static int lgdt3304_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int lgdt3304_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt3305_state *state = fe->demodulator_priv; int ret; - lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); + lg_dbg("(%d, %d)\n", p->frequency, p->modulation); if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); + ret = fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); if (lg_fail(ret)) goto fail; - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; } - ret = lgdt3305_set_modulation(state, param); + ret = lgdt3305_set_modulation(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_passband_digital_agc(state, param); + ret = lgdt3305_passband_digital_agc(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_agc_setup(state, param); + ret = lgdt3305_agc_setup(state, p); if (lg_fail(ret)) goto fail; /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */ - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: lgdt3305_write_reg(state, 0x030d, 0x00); lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f); @@ -718,7 +718,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe, case QAM_64: case QAM_256: lgdt3305_write_reg(state, 0x030d, 0x14); - ret = lgdt3305_set_if(state, param); + ret = lgdt3305_set_if(state, p); if (lg_fail(ret)) goto fail; break; @@ -727,13 +727,13 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe, } - ret = lgdt3305_spectral_inversion(state, param, + ret = lgdt3305_spectral_inversion(state, p, state->cfg->spectral_inversion ? 1 : 0); if (lg_fail(ret)) goto fail; - state->current_modulation = param->u.vsb.modulation; + state->current_modulation = p->modulation; ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); if (lg_fail(ret)) @@ -747,34 +747,34 @@ fail: return ret; } -static int lgdt3305_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int lgdt3305_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt3305_state *state = fe->demodulator_priv; int ret; - lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation); + lg_dbg("(%d, %d)\n", p->frequency, p->modulation); if (fe->ops.tuner_ops.set_params) { - ret = fe->ops.tuner_ops.set_params(fe, param); + ret = fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); if (lg_fail(ret)) goto fail; - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; } - ret = lgdt3305_set_modulation(state, param); + ret = lgdt3305_set_modulation(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_passband_digital_agc(state, param); + ret = lgdt3305_passband_digital_agc(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_set_agc_power_ref(state, param); + ret = lgdt3305_set_agc_power_ref(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_agc_setup(state, param); + ret = lgdt3305_agc_setup(state, p); if (lg_fail(ret)) goto fail; @@ -786,20 +786,20 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe, if (lg_fail(ret)) goto fail; - ret = lgdt3305_set_if(state, param); + ret = lgdt3305_set_if(state, p); if (lg_fail(ret)) goto fail; - ret = lgdt3305_spectral_inversion(state, param, + ret = lgdt3305_spectral_inversion(state, p, state->cfg->spectral_inversion ? 1 : 0); if (lg_fail(ret)) goto fail; - ret = lgdt3305_set_filter_extension(state, param); + ret = lgdt3305_set_filter_extension(state, p); if (lg_fail(ret)) goto fail; - state->current_modulation = param->u.vsb.modulation; + state->current_modulation = p->modulation; ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode); if (lg_fail(ret)) @@ -813,15 +813,15 @@ fail: return ret; } -static int lgdt3305_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int lgdt3305_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt3305_state *state = fe->demodulator_priv; lg_dbg("\n"); - param->u.vsb.modulation = state->current_modulation; - param->frequency = state->current_frequency; + p->modulation = state->current_modulation; + p->frequency = state->current_frequency; return 0; } @@ -1166,9 +1166,9 @@ fail: EXPORT_SYMBOL(lgdt3305_attach); static struct dvb_frontend_ops lgdt3304_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3304 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, @@ -1188,9 +1188,9 @@ static struct dvb_frontend_ops lgdt3304_ops = { }; static struct dvb_frontend_ops lgdt3305_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3305 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 43971e63baa7..c990d35a13dc 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -288,6 +288,8 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) int err; u8 buf[2]; + *ucblocks = 0; + switch (state->config->demod_chip) { case LGDT3302: err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, @@ -302,14 +304,16 @@ static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) "Only LGDT3302 and LGDT3303 are supported chips.\n"); err = -ENODEV; } + if (err < 0) + return err; *ucblocks = (buf[0] << 8) | buf[1]; return 0; } -static int lgdt330x_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int lgdt330x_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; /* * Array of byte pairs <address, value> * to initialize 8VSB for lgdt3303 chip 50 MHz IF @@ -343,10 +347,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 }; - int err; + int err = 0; /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - switch(param->u.vsb.modulation) { + if (state->current_modulation != p->modulation) { + switch (p->modulation) { case VSB_8: dprintk("%s: VSB_8 MODE\n", __func__); @@ -395,9 +399,14 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, } break; default: - printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, param->u.vsb.modulation); + printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __func__, p->modulation); return -1; } + if (err < 0) + printk(KERN_WARNING "lgdt330x: %s: error blasting " + "bytes to lgdt3303 for modulation type(%d)\n", + __func__, p->modulation); + /* * select serial or parallel MPEG harware interface * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 @@ -410,29 +419,29 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, sizeof(top_ctrl_cfg)); if (state->config->set_ts_params) state->config->set_ts_params(fe, 0); - state->current_modulation = param->u.vsb.modulation; + state->current_modulation = p->modulation; } /* Tune to the specified frequency */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } /* Keep track of the new frequency */ /* FIXME this is the wrong way to do this... */ /* The tuner is shared with the video4linux analog API */ - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; lgdt330x_SwReset(state); return 0; } -static int lgdt330x_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters* param) +static int lgdt330x_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgdt330x_state *state = fe->demodulator_priv; - param->frequency = state->current_frequency; + p->frequency = state->current_frequency; return 0; } @@ -762,9 +771,9 @@ error: } static struct dvb_frontend_ops lgdt3302_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name= "LG Electronics LGDT3302 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min= 54000000, .frequency_max= 858000000, .frequency_stepsize= 62500, @@ -785,9 +794,9 @@ static struct dvb_frontend_ops lgdt3302_ops = { }; static struct dvb_frontend_ops lgdt3303_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name= "LG Electronics LGDT3303 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min= 54000000, .frequency_max= 858000000, .frequency_stepsize= 62500, diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c index bb37ed289a05..2cec8041a106 100644 --- a/drivers/media/dvb/frontends/lgs8gl5.c +++ b/drivers/media/dvb/frontends/lgs8gl5.c @@ -311,18 +311,18 @@ lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int -lgs8gl5_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +lgs8gl5_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgs8gl5_state *state = fe->demodulator_priv; dprintk("%s\n", __func__); - if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) + if (p->bandwidth_hz != 8000000) return -EINVAL; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -336,22 +336,21 @@ lgs8gl5_set_frontend(struct dvb_frontend *fe, static int -lgs8gl5_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +lgs8gl5_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct lgs8gl5_state *state = fe->demodulator_priv; u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); - struct dvb_ofdm_parameters *o = &p->u.ofdm; p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; - o->code_rate_HP = FEC_1_2; - o->code_rate_LP = FEC_7_8; - o->guard_interval = GUARD_INTERVAL_1_32; - o->transmission_mode = TRANSMISSION_MODE_2K; - o->constellation = QAM_64; - o->hierarchy_information = HIERARCHY_NONE; - o->bandwidth = BANDWIDTH_8_MHZ; + p->code_rate_HP = FEC_1_2; + p->code_rate_LP = FEC_7_8; + p->guard_interval = GUARD_INTERVAL_1_32; + p->transmission_mode = TRANSMISSION_MODE_2K; + p->modulation = QAM_64; + p->hierarchy = HIERARCHY_NONE; + p->bandwidth_hz = 8000000; return 0; } @@ -413,9 +412,9 @@ EXPORT_SYMBOL(lgs8gl5_attach); static struct dvb_frontend_ops lgs8gl5_ops = { + .delsys = { SYS_DMBTH }, .info = { .name = "Legend Silicon LGS-8GL5 DMB-TH", - .type = FE_OFDM, .frequency_min = 474000000, .frequency_max = 858000000, .frequency_stepsize = 10000, diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index 1172b54689f8..4de1d3520cd2 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -669,16 +669,16 @@ static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len) return lgs8gxx_write_reg(priv, buf[0], buf[1]); } -static int lgs8gxx_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int lgs8gxx_set_fe(struct dvb_frontend *fe) { + struct lgs8gxx_state *priv = fe->demodulator_priv; dprintk("%s\n", __func__); /* set frequency */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -691,9 +691,9 @@ static int lgs8gxx_set_fe(struct dvb_frontend *fe, return 0; } -static int lgs8gxx_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fe_params) +static int lgs8gxx_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; dprintk("%s\n", __func__); /* TODO: get real readings from device */ @@ -701,21 +701,21 @@ static int lgs8gxx_get_fe(struct dvb_frontend *fe, fe_params->inversion = INVERSION_OFF; /* bandwidth */ - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fe_params->bandwidth_hz = 8000000; - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.code_rate_LP = FEC_AUTO; + fe_params->code_rate_HP = FEC_AUTO; + fe_params->code_rate_LP = FEC_AUTO; - fe_params->u.ofdm.constellation = QAM_AUTO; + fe_params->modulation = QAM_AUTO; /* transmission mode */ - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + fe_params->transmission_mode = TRANSMISSION_MODE_AUTO; /* guard interval */ - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; + fe_params->guard_interval = GUARD_INTERVAL_AUTO; /* hierarchy */ - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fe_params->hierarchy = HIERARCHY_NONE; return 0; } @@ -994,9 +994,9 @@ static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } static struct dvb_frontend_ops lgs8gxx_ops = { + .delsys = { SYS_DMBTH }, .info = { .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH", - .type = FE_OFDM, .frequency_min = 474000000, .frequency_max = 858000000, .frequency_stepsize = 10000, diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c index c283112051b1..9ae40abfd71a 100644 --- a/drivers/media/dvb/frontends/mb86a16.c +++ b/drivers/media/dvb/frontends/mb86a16.c @@ -1621,13 +1621,13 @@ err: return -EREMOTEIO; } -static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mb86a16_state *state = fe->demodulator_priv; state->frequency = p->frequency / 1000; - state->srate = p->u.qpsk.symbol_rate / 1000; + state->srate = p->symbol_rate / 1000; if (!mb86a16_set_fe(state)) { dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK"); @@ -1814,9 +1814,9 @@ static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe) } static struct dvb_frontend_ops mb86a16_ops = { + .delsys = { SYS_DVBS }, .info = { .name = "Fujitsu MB86A16 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 3000, diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c index 0f867a5055fb..7fa3e472cdca 100644 --- a/drivers/media/dvb/frontends/mb86a20s.c +++ b/drivers/media/dvb/frontends/mb86a20s.c @@ -61,244 +61,111 @@ static struct regdata mb86a20s_init[] = { { 0x70, 0xff }, { 0x08, 0x01 }, { 0x09, 0x3e }, - { 0x50, 0xd1 }, - { 0x51, 0x22 }, + { 0x50, 0xd1 }, { 0x51, 0x22 }, { 0x39, 0x01 }, { 0x71, 0x00 }, - { 0x28, 0x2a }, - { 0x29, 0x00 }, - { 0x2a, 0xff }, - { 0x2b, 0x80 }, - { 0x28, 0x20 }, - { 0x29, 0x33 }, - { 0x2a, 0xdf }, - { 0x2b, 0xa9 }, + { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 }, + { 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 }, + { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 }, { 0x3b, 0x21 }, { 0x3c, 0x3a }, { 0x01, 0x0d }, - { 0x04, 0x08 }, - { 0x05, 0x05 }, - { 0x04, 0x0e }, - { 0x05, 0x00 }, - { 0x04, 0x0f }, - { 0x05, 0x14 }, - { 0x04, 0x0b }, - { 0x05, 0x8c }, - { 0x04, 0x00 }, - { 0x05, 0x00 }, - { 0x04, 0x01 }, - { 0x05, 0x07 }, - { 0x04, 0x02 }, - { 0x05, 0x0f }, - { 0x04, 0x03 }, - { 0x05, 0xa0 }, - { 0x04, 0x09 }, - { 0x05, 0x00 }, - { 0x04, 0x0a }, - { 0x05, 0xff }, - { 0x04, 0x27 }, - { 0x05, 0x64 }, - { 0x04, 0x28 }, - { 0x05, 0x00 }, - { 0x04, 0x1e }, - { 0x05, 0xff }, - { 0x04, 0x29 }, - { 0x05, 0x0a }, - { 0x04, 0x32 }, - { 0x05, 0x0a }, - { 0x04, 0x14 }, - { 0x05, 0x02 }, - { 0x04, 0x04 }, - { 0x05, 0x00 }, - { 0x04, 0x05 }, - { 0x05, 0x22 }, - { 0x04, 0x06 }, - { 0x05, 0x0e }, - { 0x04, 0x07 }, - { 0x05, 0xd8 }, - { 0x04, 0x12 }, - { 0x05, 0x00 }, - { 0x04, 0x13 }, - { 0x05, 0xff }, + { 0x04, 0x08 }, { 0x05, 0x05 }, + { 0x04, 0x0e }, { 0x05, 0x00 }, + { 0x04, 0x0f }, { 0x05, 0x14 }, + { 0x04, 0x0b }, { 0x05, 0x8c }, + { 0x04, 0x00 }, { 0x05, 0x00 }, + { 0x04, 0x01 }, { 0x05, 0x07 }, + { 0x04, 0x02 }, { 0x05, 0x0f }, + { 0x04, 0x03 }, { 0x05, 0xa0 }, + { 0x04, 0x09 }, { 0x05, 0x00 }, + { 0x04, 0x0a }, { 0x05, 0xff }, + { 0x04, 0x27 }, { 0x05, 0x64 }, + { 0x04, 0x28 }, { 0x05, 0x00 }, + { 0x04, 0x1e }, { 0x05, 0xff }, + { 0x04, 0x29 }, { 0x05, 0x0a }, + { 0x04, 0x32 }, { 0x05, 0x0a }, + { 0x04, 0x14 }, { 0x05, 0x02 }, + { 0x04, 0x04 }, { 0x05, 0x00 }, + { 0x04, 0x05 }, { 0x05, 0x22 }, + { 0x04, 0x06 }, { 0x05, 0x0e }, + { 0x04, 0x07 }, { 0x05, 0xd8 }, + { 0x04, 0x12 }, { 0x05, 0x00 }, + { 0x04, 0x13 }, { 0x05, 0xff }, + { 0x04, 0x15 }, { 0x05, 0x4e }, + { 0x04, 0x16 }, { 0x05, 0x20 }, { 0x52, 0x01 }, - { 0x50, 0xa7 }, - { 0x51, 0x00 }, - { 0x50, 0xa8 }, - { 0x51, 0xff }, - { 0x50, 0xa9 }, - { 0x51, 0xff }, - { 0x50, 0xaa }, - { 0x51, 0x00 }, - { 0x50, 0xab }, - { 0x51, 0xff }, - { 0x50, 0xac }, - { 0x51, 0xff }, - { 0x50, 0xad }, - { 0x51, 0x00 }, - { 0x50, 0xae }, - { 0x51, 0xff }, - { 0x50, 0xaf }, - { 0x51, 0xff }, + { 0x50, 0xa7 }, { 0x51, 0xff }, + { 0x50, 0xa8 }, { 0x51, 0xff }, + { 0x50, 0xa9 }, { 0x51, 0xff }, + { 0x50, 0xaa }, { 0x51, 0xff }, + { 0x50, 0xab }, { 0x51, 0xff }, + { 0x50, 0xac }, { 0x51, 0xff }, + { 0x50, 0xad }, { 0x51, 0xff }, + { 0x50, 0xae }, { 0x51, 0xff }, + { 0x50, 0xaf }, { 0x51, 0xff }, { 0x5e, 0x07 }, - { 0x50, 0xdc }, - { 0x51, 0x01 }, - { 0x50, 0xdd }, - { 0x51, 0xf4 }, - { 0x50, 0xde }, - { 0x51, 0x01 }, - { 0x50, 0xdf }, - { 0x51, 0xf4 }, - { 0x50, 0xe0 }, - { 0x51, 0x01 }, - { 0x50, 0xe1 }, - { 0x51, 0xf4 }, - { 0x50, 0xb0 }, - { 0x51, 0x07 }, - { 0x50, 0xb2 }, - { 0x51, 0xff }, - { 0x50, 0xb3 }, - { 0x51, 0xff }, - { 0x50, 0xb4 }, - { 0x51, 0xff }, - { 0x50, 0xb5 }, - { 0x51, 0xff }, - { 0x50, 0xb6 }, - { 0x51, 0xff }, - { 0x50, 0xb7 }, - { 0x51, 0xff }, - { 0x50, 0x50 }, - { 0x51, 0x02 }, - { 0x50, 0x51 }, - { 0x51, 0x04 }, + { 0x50, 0xdc }, { 0x51, 0x01 }, + { 0x50, 0xdd }, { 0x51, 0xf4 }, + { 0x50, 0xde }, { 0x51, 0x01 }, + { 0x50, 0xdf }, { 0x51, 0xf4 }, + { 0x50, 0xe0 }, { 0x51, 0x01 }, + { 0x50, 0xe1 }, { 0x51, 0xf4 }, + { 0x50, 0xb0 }, { 0x51, 0x07 }, + { 0x50, 0xb2 }, { 0x51, 0xff }, + { 0x50, 0xb3 }, { 0x51, 0xff }, + { 0x50, 0xb4 }, { 0x51, 0xff }, + { 0x50, 0xb5 }, { 0x51, 0xff }, + { 0x50, 0xb6 }, { 0x51, 0xff }, + { 0x50, 0xb7 }, { 0x51, 0xff }, + { 0x50, 0x50 }, { 0x51, 0x02 }, + { 0x50, 0x51 }, { 0x51, 0x04 }, { 0x45, 0x04 }, { 0x48, 0x04 }, - { 0x50, 0xd5 }, - { 0x51, 0x01 }, /* Serial */ - { 0x50, 0xd6 }, - { 0x51, 0x1f }, - { 0x50, 0xd2 }, - { 0x51, 0x03 }, - { 0x50, 0xd7 }, - { 0x51, 0x3f }, + { 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */ + { 0x50, 0xd6 }, { 0x51, 0x1f }, + { 0x50, 0xd2 }, { 0x51, 0x03 }, + { 0x50, 0xd7 }, { 0x51, 0x3f }, + { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 }, + { 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c }, + { 0x04, 0x40 }, { 0x05, 0x01 }, + { 0x28, 0x00 }, { 0x29, 0x10 }, + { 0x28, 0x05 }, { 0x29, 0x02 }, { 0x1c, 0x01 }, - { 0x28, 0x06 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x03 }, - { 0x28, 0x07 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0d }, - { 0x28, 0x08 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x02 }, - { 0x28, 0x09 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x01 }, - { 0x28, 0x0a }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x21 }, - { 0x28, 0x0b }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x29 }, - { 0x28, 0x0c }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x16 }, - { 0x28, 0x0d }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x31 }, - { 0x28, 0x0e }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0e }, - { 0x28, 0x0f }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x4e }, - { 0x28, 0x10 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x46 }, - { 0x28, 0x11 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x0f }, - { 0x28, 0x12 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x56 }, - { 0x28, 0x13 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x35 }, - { 0x28, 0x14 }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0xbe }, - { 0x28, 0x15 }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0x84 }, - { 0x28, 0x16 }, - { 0x29, 0x00 }, - { 0x2a, 0x03 }, - { 0x2b, 0xee }, - { 0x28, 0x17 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x98 }, - { 0x28, 0x18 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - { 0x2b, 0x9f }, - { 0x28, 0x19 }, - { 0x29, 0x00 }, - { 0x2a, 0x07 }, - { 0x2b, 0xb2 }, - { 0x28, 0x1a }, - { 0x29, 0x00 }, - { 0x2a, 0x06 }, - { 0x2b, 0xc2 }, - { 0x28, 0x1b }, - { 0x29, 0x00 }, - { 0x2a, 0x07 }, - { 0x2b, 0x4a }, - { 0x28, 0x1c }, - { 0x29, 0x00 }, - { 0x2a, 0x01 }, - { 0x2b, 0xbc }, - { 0x28, 0x1d }, - { 0x29, 0x00 }, - { 0x2a, 0x04 }, - { 0x2b, 0xba }, - { 0x28, 0x1e }, - { 0x29, 0x00 }, - { 0x2a, 0x06 }, - { 0x2b, 0x14 }, - { 0x50, 0x1e }, - { 0x51, 0x5d }, - { 0x50, 0x22 }, - { 0x51, 0x00 }, - { 0x50, 0x23 }, - { 0x51, 0xc8 }, - { 0x50, 0x24 }, - { 0x51, 0x00 }, - { 0x50, 0x25 }, - { 0x51, 0xf0 }, - { 0x50, 0x26 }, - { 0x51, 0x00 }, - { 0x50, 0x27 }, - { 0x51, 0xc3 }, - { 0x50, 0x39 }, - { 0x51, 0x02 }, - { 0x50, 0xd5 }, - { 0x51, 0x01 }, + { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 }, + { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d }, + { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, + { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 }, + { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 }, + { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 }, + { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, + { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 }, + { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e }, + { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e }, + { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 }, + { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, + { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 }, + { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 }, + { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe }, + { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 }, + { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee }, + { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 }, + { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f }, + { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 }, + { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 }, + { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a }, + { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc }, + { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba }, + { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 }, + { 0x50, 0x1e }, { 0x51, 0x5d }, + { 0x50, 0x22 }, { 0x51, 0x00 }, + { 0x50, 0x23 }, { 0x51, 0xc8 }, + { 0x50, 0x24 }, { 0x51, 0x00 }, + { 0x50, 0x25 }, { 0x51, 0xf0 }, + { 0x50, 0x26 }, { 0x51, 0x00 }, + { 0x50, 0x27 }, { 0x51, 0xc3 }, + { 0x50, 0x39 }, { 0x51, 0x02 }, + { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 }, { 0xd0, 0x00 }, }; @@ -485,18 +352,23 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; } -static int mb86a20s_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mb86a20s_set_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; int rc; +#if 0 + /* + * FIXME: Properly implement the set frontend properties + */ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; +#endif dprintk("\n"); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); dprintk("Calling tuner set parameters\n"); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); /* * Make it more reliable: if, for some reason, the initial @@ -520,22 +392,212 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe, return rc; } -static int mb86a20s_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mb86a20s_get_modulation(struct mb86a20s_state *state, + unsigned layer) +{ + int rc; + static unsigned char reg[] = { + [0] = 0x86, /* Layer A */ + [1] = 0x8a, /* Layer B */ + [2] = 0x8e, /* Layer C */ + }; + + if (layer > ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + switch ((rc & 0x70) >> 4) { + case 0: + return DQPSK; + case 1: + return QPSK; + case 2: + return QAM_16; + case 3: + return QAM_64; + default: + return QAM_AUTO; + } +} + +static int mb86a20s_get_fec(struct mb86a20s_state *state, + unsigned layer) { + int rc; - /* FIXME: For now, it does nothing */ + static unsigned char reg[] = { + [0] = 0x87, /* Layer A */ + [1] = 0x8b, /* Layer B */ + [2] = 0x8f, /* Layer C */ + }; - fe->dtv_property_cache.bandwidth_hz = 6000000; - fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; - fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; - fe->dtv_property_cache.isdbt_partial_reception = 0; + if (layer > ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + switch (rc) { + case 0: + return FEC_1_2; + case 1: + return FEC_2_3; + case 2: + return FEC_3_4; + case 3: + return FEC_5_6; + case 4: + return FEC_7_8; + default: + return FEC_AUTO; + } +} + +static int mb86a20s_get_interleaving(struct mb86a20s_state *state, + unsigned layer) +{ + int rc; + + static unsigned char reg[] = { + [0] = 0x88, /* Layer A */ + [1] = 0x8c, /* Layer B */ + [2] = 0x90, /* Layer C */ + }; + + if (layer > ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + if (rc > 3) + return -EINVAL; /* Not used */ + return rc; +} + +static int mb86a20s_get_segment_count(struct mb86a20s_state *state, + unsigned layer) +{ + int rc, count; + + static unsigned char reg[] = { + [0] = 0x89, /* Layer A */ + [1] = 0x8d, /* Layer B */ + [2] = 0x91, /* Layer C */ + }; + + if (layer > ARRAY_SIZE(reg)) + return -EINVAL; + rc = mb86a20s_writereg(state, 0x6d, reg[layer]); + if (rc < 0) + return rc; + rc = mb86a20s_readreg(state, 0x6e); + if (rc < 0) + return rc; + count = (rc >> 4) & 0x0f; + + return count; +} + +static int mb86a20s_get_frontend(struct dvb_frontend *fe) +{ + struct mb86a20s_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int i, rc; + + /* Fixed parameters */ + p->delivery_system = SYS_ISDBT; + p->bandwidth_hz = 6000000; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* Check for partial reception */ + rc = mb86a20s_writereg(state, 0x6d, 0x85); + if (rc >= 0) + rc = mb86a20s_readreg(state, 0x6e); + if (rc >= 0) + p->isdbt_partial_reception = (rc & 0x10) ? 1 : 0; + + /* Get per-layer data */ + p->isdbt_layer_enabled = 0; + for (i = 0; i < 3; i++) { + rc = mb86a20s_get_segment_count(state, i); + if (rc >= 0 && rc < 14) + p->layer[i].segment_count = rc; + if (rc == 0x0f) + continue; + p->isdbt_layer_enabled |= 1 << i; + rc = mb86a20s_get_modulation(state, i); + if (rc >= 0) + p->layer[i].modulation = rc; + rc = mb86a20s_get_fec(state, i); + if (rc >= 0) + p->layer[i].fec = rc; + rc = mb86a20s_get_interleaving(state, i); + if (rc >= 0) + p->layer[i].interleaving = rc; + } + + p->isdbt_sb_mode = 0; + rc = mb86a20s_writereg(state, 0x6d, 0x84); + if ((rc >= 0) && ((rc & 0x60) == 0x20)) { + p->isdbt_sb_mode = 1; + /* At least, one segment should exist */ + if (!p->isdbt_sb_segment_count) + p->isdbt_sb_segment_count = 1; + } else + p->isdbt_sb_segment_count = 0; + + /* Get transmission mode and guard interval */ + p->transmission_mode = TRANSMISSION_MODE_AUTO; + p->guard_interval = GUARD_INTERVAL_AUTO; + rc = mb86a20s_readreg(state, 0x07); + if (rc >= 0) { + if ((rc & 0x60) == 0x20) { + switch (rc & 0x0c >> 2) { + case 0: + p->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + p->transmission_mode = TRANSMISSION_MODE_4K; + break; + case 2: + p->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + } + if (!(rc & 0x10)) { + switch (rc & 0x3) { + case 0: + p->guard_interval = GUARD_INTERVAL_1_4; + break; + case 1: + p->guard_interval = GUARD_INTERVAL_1_8; + break; + case 2: + p->guard_interval = GUARD_INTERVAL_1_16; + break; + } + } + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); return 0; } static int mb86a20s_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) @@ -544,8 +606,8 @@ static int mb86a20s_tune(struct dvb_frontend *fe, dprintk("\n"); - if (params != NULL) - rc = mb86a20s_set_frontend(fe, params); + if (re_tune) + rc = mb86a20s_set_frontend(fe); if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) mb86a20s_read_status(fe, status); @@ -608,10 +670,10 @@ error: EXPORT_SYMBOL(mb86a20s_attach); static struct dvb_frontend_ops mb86a20s_ops = { + .delsys = { SYS_ISDBT }, /* Use dib8000 values per default */ .info = { .name = "Fujitsu mb86A20s", - .type = FE_OFDM, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER | 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 | diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 83e6f1a1b700..e20bf13aa860 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -531,9 +531,9 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) return 0; } -static int mt312_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mt312_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[5], config_val; @@ -553,16 +553,16 @@ static int mt312_set_frontend(struct dvb_frontend *fe, || (p->inversion > INVERSION_ON)) return -EINVAL; - if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) - || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) + if ((p->symbol_rate < fe->ops.info.symbol_rate_min) + || (p->symbol_rate > fe->ops.info.symbol_rate_max)) return -EINVAL; - if ((p->u.qpsk.fec_inner < FEC_NONE) - || (p->u.qpsk.fec_inner > FEC_AUTO)) + if ((p->fec_inner < FEC_NONE) + || (p->fec_inner > FEC_AUTO)) return -EINVAL; - if ((p->u.qpsk.fec_inner == FEC_4_5) - || (p->u.qpsk.fec_inner == FEC_8_9)) + if ((p->fec_inner == FEC_4_5) + || (p->fec_inner == FEC_8_9)) return -EINVAL; switch (state->id) { @@ -574,7 +574,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe, ret = mt312_readreg(state, CONFIG, &config_val); if (ret < 0) return ret; - if (p->u.qpsk.symbol_rate >= 30000000) { + if (p->symbol_rate >= 30000000) { /* Note that 30MS/s should use 90MHz */ if (state->freq_mult == 6) { /* We are running 60MHz */ @@ -603,25 +603,25 @@ static int mt312_set_frontend(struct dvb_frontend *fe, } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } /* sr = (u16)(sr * 256.0 / 1000000.0) */ - sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); + sr = mt312_div(p->symbol_rate * 4, 15625); /* SYM_RATE */ buf[0] = (sr >> 8) & 0x3f; buf[1] = (sr >> 0) & 0xff; /* VIT_MODE */ - buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner]; + buf[2] = inv_tab[p->inversion] | fec_tab[p->fec_inner]; /* QPSK_CTRL */ buf[3] = 0x40; /* swap I and Q before QPSK demodulation */ - if (p->u.qpsk.symbol_rate < 10000000) + if (p->symbol_rate < 10000000) buf[3] |= 0x04; /* use afc mode */ /* GO */ @@ -636,9 +636,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe, return 0; } -static int mt312_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int mt312_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mt312_state *state = fe->demodulator_priv; int ret; @@ -646,11 +646,11 @@ static int mt312_get_frontend(struct dvb_frontend *fe, if (ret < 0) return ret; - ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); + ret = mt312_get_symbol_rate(state, &p->symbol_rate); if (ret < 0) return ret; - ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); + ret = mt312_get_code_rate(state, &p->fec_inner); if (ret < 0) return ret; @@ -738,10 +738,9 @@ static void mt312_release(struct dvb_frontend *fe) #define MT312_SYS_CLK 90000000UL /* 90 MHz */ static struct dvb_frontend_ops mt312_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Zarlink ???? DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, /* FIXME: adjust freq to real used xtal */ diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 319672f8e1a7..2c3b50e828d7 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -111,20 +111,20 @@ static int mt352_sleep(struct dvb_frontend* fe) } static void mt352_calc_nominal_rate(struct mt352_state* state, - enum fe_bandwidth bandwidth, + u32 bandwidth, unsigned char *buf) { u32 adc_clock = 20480; /* 20.340 MHz */ u32 bw,value; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: bw = 6; break; - case BANDWIDTH_7_MHZ: + case 7000000: bw = 7; break; - case BANDWIDTH_8_MHZ: + case 8000000: default: bw = 8; break; @@ -166,15 +166,14 @@ static void mt352_calc_input_freq(struct mt352_state* state, buf[1] = lsb(value); } -static int mt352_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int mt352_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *op = &fe->dtv_property_cache; struct mt352_state* state = fe->demodulator_priv; unsigned char buf[13]; static unsigned char tuner_go[] = { 0x5d, 0x01 }; static unsigned char fsm_go[] = { 0x5e, 0x01 }; unsigned int tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; switch (op->code_rate_HP) { case FEC_2_3: @@ -213,14 +212,14 @@ static int mt352_set_parameters(struct dvb_frontend* fe, case FEC_AUTO: break; case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) + if (op->hierarchy == HIERARCHY_AUTO || + op->hierarchy == HIERARCHY_NONE) break; default: return -EINVAL; } - switch (op->constellation) { + switch (op->modulation) { case QPSK: break; case QAM_AUTO: @@ -262,7 +261,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe, return -EINVAL; } - switch (op->hierarchy_information) { + switch (op->hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: break; @@ -288,12 +287,12 @@ static int mt352_set_parameters(struct dvb_frontend* fe, buf[3] = 0x50; // old // buf[3] = 0xf4; // pinnacle - mt352_calc_nominal_rate(state, op->bandwidth, buf+4); + mt352_calc_nominal_rate(state, op->bandwidth_hz, buf+4); mt352_calc_input_freq(state, buf+6); if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -302,7 +301,7 @@ static int mt352_set_parameters(struct dvb_frontend* fe, _mt352_write(fe, fsm_go, 2); } else { if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5); + fe->ops.tuner_ops.calc_regs(fe, buf+8, 5); buf[8] <<= 1; _mt352_write(fe, buf, sizeof(buf)); _mt352_write(fe, tuner_go, 2); @@ -312,14 +311,13 @@ static int mt352_set_parameters(struct dvb_frontend* fe, return 0; } -static int mt352_get_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int mt352_get_parameters(struct dvb_frontend* fe) { + struct dtv_frontend_properties *op = &fe->dtv_property_cache; struct mt352_state* state = fe->demodulator_priv; u16 tps; u16 div; u8 trl; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; static const u8 tps_fec_to_api[8] = { FEC_1_2, @@ -348,16 +346,16 @@ static int mt352_get_parameters(struct dvb_frontend* fe, switch ( (tps >> 13) & 3) { case 0: - op->constellation = QPSK; + op->modulation = QPSK; break; case 1: - op->constellation = QAM_16; + op->modulation = QAM_16; break; case 2: - op->constellation = QAM_64; + op->modulation = QAM_64; break; default: - op->constellation = QAM_AUTO; + op->modulation = QAM_AUTO; break; } @@ -385,36 +383,36 @@ static int mt352_get_parameters(struct dvb_frontend* fe, switch ( (tps >> 10) & 7) { case 0: - op->hierarchy_information = HIERARCHY_NONE; + op->hierarchy = HIERARCHY_NONE; break; case 1: - op->hierarchy_information = HIERARCHY_1; + op->hierarchy = HIERARCHY_1; break; case 2: - op->hierarchy_information = HIERARCHY_2; + op->hierarchy = HIERARCHY_2; break; case 3: - op->hierarchy_information = HIERARCHY_4; + op->hierarchy = HIERARCHY_4; break; default: - op->hierarchy_information = HIERARCHY_AUTO; + op->hierarchy = HIERARCHY_AUTO; break; } - param->frequency = ( 500 * (div - IF_FREQUENCYx6) ) / 3 * 1000; + op->frequency = (500 * (div - IF_FREQUENCYx6)) / 3 * 1000; if (trl == 0x72) - op->bandwidth = BANDWIDTH_8_MHZ; + op->bandwidth_hz = 8000000; else if (trl == 0x64) - op->bandwidth = BANDWIDTH_7_MHZ; + op->bandwidth_hz = 7000000; else - op->bandwidth = BANDWIDTH_6_MHZ; + op->bandwidth_hz = 6000000; if (mt352_read_register(state, STATUS_2) & 0x02) - param->inversion = INVERSION_OFF; + op->inversion = INVERSION_OFF; else - param->inversion = INVERSION_ON; + op->inversion = INVERSION_ON; return 0; } @@ -569,10 +567,9 @@ error: } static struct dvb_frontend_ops mt352_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Zarlink MT352 DVB-T", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index eac20650499f..49ca78d883b1 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -528,9 +528,9 @@ static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware return 0; }; -static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int nxt200x_setup_frontend_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct nxt200x_state* state = fe->demodulator_priv; u8 buf[5]; @@ -546,7 +546,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* set additional params */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: case QAM_256: /* Set punctured clock for QAM */ @@ -566,7 +566,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, if (fe->ops.tuner_ops.calc_regs) { /* get tuning information */ - fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); + fe->ops.tuner_ops.calc_regs(fe, buf, 5); /* write frequency information */ nxt200x_writetuner(state, buf); @@ -576,7 +576,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, nxt200x_agc_reset(state); /* set target power level */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: case QAM_256: buf[0] = 0x74; @@ -620,7 +620,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* write sdmx input */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: buf[0] = 0x68; break; @@ -714,7 +714,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* write agc ucgp0 */ - switch (p->u.vsb.modulation) { + switch (p->modulation) { case QAM_64: buf[0] = 0x02; break; @@ -1203,10 +1203,9 @@ error: } static struct dvb_frontend_ops nxt200x_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Nextwave NXT200X VSB/QAM frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 860000000, .frequency_stepsize = 166666, /* stepsize is just a guess */ diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index 6599b8fea9e9..90ae6c72c0e3 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -81,22 +81,21 @@ static void nxt6000_reset(struct nxt6000_state* state) nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT); } -static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth) +static int nxt6000_set_bandwidth(struct nxt6000_state *state, u32 bandwidth) { u16 nominal_rate; int result; switch (bandwidth) { - - case BANDWIDTH_6_MHZ: + case 6000000: nominal_rate = 0x55B7; break; - case BANDWIDTH_7_MHZ: + case 7000000: nominal_rate = 0x6400; break; - case BANDWIDTH_8_MHZ: + case 8000000: nominal_rate = 0x7249; break; @@ -457,23 +456,31 @@ static int nxt6000_init(struct dvb_frontend* fe) return 0; } -static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +static int nxt6000_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct nxt6000_state* state = fe->demodulator_priv; int result; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) + result = nxt6000_set_bandwidth(state, p->bandwidth_hz); + if (result < 0) return result; - if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0) + + result = nxt6000_set_guard_interval(state, p->guard_interval); + if (result < 0) return result; - if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0) + + result = nxt6000_set_transmission_mode(state, p->transmission_mode); + if (result < 0) return result; - if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) + + result = nxt6000_set_inversion(state, p->inversion); + if (result < 0) return result; msleep(500); @@ -566,10 +573,9 @@ error: } static struct dvb_frontend_ops nxt6000_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "NxtWave NXT6000 DVB-T", - .type = FE_OFDM, .frequency_min = 0, .frequency_max = 863250000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 38e67accb8c3..5ef921823c15 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -306,9 +306,9 @@ static int modulation_fw_class(fe_modulation_t modulation) } } -static int or51132_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int or51132_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret; struct or51132_state* state = fe->demodulator_priv; const struct firmware *fw; @@ -317,8 +317,8 @@ static int or51132_set_parameters(struct dvb_frontend* fe, /* Upload new firmware only if we need a different one */ if (modulation_fw_class(state->current_modulation) != - modulation_fw_class(param->u.vsb.modulation)) { - switch(modulation_fw_class(param->u.vsb.modulation)) { + modulation_fw_class(p->modulation)) { + switch (modulation_fw_class(p->modulation)) { case MOD_FWCLASS_VSB: dprintk("set_parameters VSB MODE\n"); fwname = OR51132_VSB_FIRMWARE; @@ -335,7 +335,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe, break; default: printk("or51132: Modulation type(%d) UNSUPPORTED\n", - param->u.vsb.modulation); + p->modulation); return -1; } printk("or51132: Waiting for firmware upload(%s)...\n", @@ -357,13 +357,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe, state->config->set_ts_params(fe, clock_mode); } /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - state->current_modulation = param->u.vsb.modulation; + if (state->current_modulation != p->modulation) { + state->current_modulation = p->modulation; or51132_setmode(fe); } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -371,13 +371,13 @@ static int or51132_set_parameters(struct dvb_frontend* fe, or51132_setmode(fe); /* Update current frequency */ - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; return 0; } -static int or51132_get_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int or51132_get_parameters(struct dvb_frontend* fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct or51132_state* state = fe->demodulator_priv; int status; int retry = 1; @@ -389,21 +389,28 @@ start: return -EREMOTEIO; } switch(status&0xff) { - case 0x06: param->u.vsb.modulation = VSB_8; break; - case 0x43: param->u.vsb.modulation = QAM_64; break; - case 0x45: param->u.vsb.modulation = QAM_256; break; - default: - if (retry--) goto start; - printk(KERN_WARNING "or51132: unknown status 0x%02x\n", - status&0xff); - return -EREMOTEIO; + case 0x06: + p->modulation = VSB_8; + break; + case 0x43: + p->modulation = QAM_64; + break; + case 0x45: + p->modulation = QAM_256; + break; + default: + if (retry--) + goto start; + printk(KERN_WARNING "or51132: unknown status 0x%02x\n", + status&0xff); + return -EREMOTEIO; } /* FIXME: Read frequency from frontend, take AFC into account */ - param->frequency = state->current_frequency; + p->frequency = state->current_frequency; /* FIXME: How to read inversion setting? Receiver 6 register? */ - param->inversion = INVERSION_AUTO; + p->inversion = INVERSION_AUTO; return 0; } @@ -579,10 +586,9 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, } static struct dvb_frontend_ops or51132_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Oren OR51132 VSB/QAM Frontend", - .type = FE_ATSC, .frequency_min = 44000000, .frequency_max = 958000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index c709ce6771c8..c625b57b4333 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -218,15 +218,15 @@ static int or51211_setmode(struct dvb_frontend* fe, int mode) return 0; } -static int or51211_set_parameters(struct dvb_frontend* fe, - struct dvb_frontend_parameters *param) +static int or51211_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct or51211_state* state = fe->demodulator_priv; /* Change only if we are actually changing the channel */ - if (state->current_frequency != param->frequency) { + if (state->current_frequency != p->frequency) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -234,7 +234,7 @@ static int or51211_set_parameters(struct dvb_frontend* fe, or51211_setmode(fe,0); /* Update current frequency */ - state->current_frequency = param->frequency; + state->current_frequency = p->frequency; } return 0; } @@ -544,10 +544,9 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, } static struct dvb_frontend_ops or51211_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Oren OR51211 VSB Frontend", - .type = FE_ATSC, .frequency_min = 44000000, .frequency_max = 958000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 0e2f61a8978f..f71b06221e14 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -631,9 +631,9 @@ static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1409_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1409_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1409_state *state = fe->demodulator_priv; dprintk("%s(frequency=%d)\n", __func__, p->frequency); @@ -642,12 +642,12 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe, state->current_frequency = p->frequency; - s5h1409_enable_modulation(fe, p->u.vsb.modulation); + s5h1409_enable_modulation(fe, p->modulation); if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -879,7 +879,36 @@ static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr) static int s5h1409_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { - return s5h1409_read_snr(fe, signal_strength); + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + u16 snr; + u32 tmp; + int ret = s5h1409_read_snr(fe, &snr); + + *signal_strength = 0; + + if (0 == ret) { + /* The following calculation method was chosen + * purely for the sake of code re-use from the + * other demod drivers that use this method */ + + /* Convert from SNR in dB * 10 to 8.24 fixed-point */ + tmp = (snr * ((1 << 24) / 10)); + + /* Convert from 8.24 fixed-point to + * scale the range 0 - 35*2^24 into 0 - 65535*/ + if (tmp >= 8960 * 0x10000) + *signal_strength = 0xffff; + else + *signal_strength = tmp / 8960; + } + + return ret; } static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -896,13 +925,13 @@ static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber) return s5h1409_read_ucblocks(fe, ber); } -static int s5h1409_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1409_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1409_state *state = fe->demodulator_priv; p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; + p->modulation = state->current_modulation; return 0; } @@ -967,10 +996,9 @@ error: EXPORT_SYMBOL(s5h1409_attach); static struct dvb_frontend_ops s5h1409_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Samsung S5H1409 QAM/8VSB Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c index d8adf1e32019..6cc4b7a9dd60 100644 --- a/drivers/media/dvb/frontends/s5h1411.c +++ b/drivers/media/dvb/frontends/s5h1411.c @@ -585,9 +585,9 @@ static int s5h1411_register_reset(struct dvb_frontend *fe) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1411_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1411_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1411_state *state = fe->demodulator_priv; dprintk("%s(frequency=%d)\n", __func__, p->frequency); @@ -596,13 +596,13 @@ static int s5h1411_set_frontend(struct dvb_frontend *fe, state->current_frequency = p->frequency; - s5h1411_enable_modulation(fe, p->u.vsb.modulation); + s5h1411_enable_modulation(fe, p->modulation); if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -794,7 +794,36 @@ static int s5h1411_read_snr(struct dvb_frontend *fe, u16 *snr) static int s5h1411_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) { - return s5h1411_read_snr(fe, signal_strength); + /* borrowed from lgdt330x.c + * + * Calculate strength from SNR up to 35dB + * Even though the SNR can go higher than 35dB, + * there is some comfort factor in having a range of + * strong signals that can show at 100% + */ + u16 snr; + u32 tmp; + int ret = s5h1411_read_snr(fe, &snr); + + *signal_strength = 0; + + if (0 == ret) { + /* The following calculation method was chosen + * purely for the sake of code re-use from the + * other demod drivers that use this method */ + + /* Convert from SNR in dB * 10 to 8.24 fixed-point */ + tmp = (snr * ((1 << 24) / 10)); + + /* Convert from 8.24 fixed-point to + * scale the range 0 - 35*2^24 into 0 - 65535*/ + if (tmp >= 8960 * 0x10000) + *signal_strength = 0xffff; + else + *signal_strength = tmp / 8960; + } + + return ret; } static int s5h1411_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) @@ -811,13 +840,13 @@ static int s5h1411_read_ber(struct dvb_frontend *fe, u32 *ber) return s5h1411_read_ucblocks(fe, ber); } -static int s5h1411_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1411_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1411_state *state = fe->demodulator_priv; p->frequency = state->current_frequency; - p->u.vsb.modulation = state->current_modulation; + p->modulation = state->current_modulation; return 0; } @@ -886,10 +915,9 @@ error: EXPORT_SYMBOL(s5h1411_attach); static struct dvb_frontend_ops s5h1411_ops = { - + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Samsung S5H1411 QAM/8VSB Frontend", - .type = FE_ATSC, .frequency_min = 54000000, .frequency_max = 858000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 3879d2e378aa..2322257c69ae 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -472,15 +472,15 @@ static void s5h1420_reset(struct s5h1420_state* state) } static void s5h1420_setsymbolrate(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) + struct dtv_frontend_properties *p) { u8 v; u64 val; dprintk("enter %s\n", __func__); - val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); - if (p->u.qpsk.symbol_rate < 29000000) + val = ((u64) p->symbol_rate / 1000ULL) * (1ULL<<24); + if (p->symbol_rate < 29000000) val *= 2; do_div(val, (state->fclk / 1000)); @@ -543,7 +543,7 @@ static int s5h1420_getfreqoffset(struct s5h1420_state* state) } static void s5h1420_setfec_inversion(struct s5h1420_state* state, - struct dvb_frontend_parameters *p) + struct dtv_frontend_properties *p) { u8 inversion = 0; u8 vit08, vit09; @@ -555,11 +555,11 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state, else if (p->inversion == INVERSION_ON) inversion = state->config->invert ? 0 : 0x08; - if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { + if ((p->fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { vit08 = 0x3f; vit09 = 0; } else { - switch(p->u.qpsk.fec_inner) { + switch (p->fec_inner) { case FEC_1_2: vit08 = 0x01; vit09 = 0x10; break; @@ -628,9 +628,9 @@ static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) return INVERSION_OFF; } -static int s5h1420_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int s5h1420_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1420_state* state = fe->demodulator_priv; int frequency_delta; struct dvb_frontend_tune_settings fesettings; @@ -639,17 +639,16 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, dprintk("enter %s\n", __func__); /* check if we should do a fast-tune */ - memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); s5h1420_get_tune_settings(fe, &fesettings); frequency_delta = p->frequency - state->tunedfreq; if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) && (frequency_delta != 0) && - (state->fec_inner == p->u.qpsk.fec_inner) && - (state->symbol_rate == p->u.qpsk.symbol_rate)) { + (state->fec_inner == p->fec_inner) && + (state->symbol_rate == p->symbol_rate)) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (fe->ops.tuner_ops.get_frequency) { @@ -669,13 +668,13 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_reset(state); /* set s5h1420 fclk PLL according to desired symbol rate */ - if (p->u.qpsk.symbol_rate > 33000000) + if (p->symbol_rate > 33000000) state->fclk = 80000000; - else if (p->u.qpsk.symbol_rate > 28500000) + else if (p->symbol_rate > 28500000) state->fclk = 59000000; - else if (p->u.qpsk.symbol_rate > 25000000) + else if (p->symbol_rate > 25000000) state->fclk = 86000000; - else if (p->u.qpsk.symbol_rate > 1900000) + else if (p->symbol_rate > 1900000) state->fclk = 88000000; else state->fclk = 44000000; @@ -705,7 +704,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); /* TODO DC offset removal, config parameter ? */ - if (p->u.qpsk.symbol_rate > 29000000) + if (p->symbol_rate > 29000000) s5h1420_writereg(state, QPSK01, 0xae | 0x10); else s5h1420_writereg(state, QPSK01, 0xac | 0x10); @@ -718,15 +717,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_writereg(state, Loop01, 0xF0); s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */ s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */ - if (p->u.qpsk.symbol_rate > 20000000) + if (p->symbol_rate > 20000000) s5h1420_writereg(state, Loop04, 0x79); else s5h1420_writereg(state, Loop04, 0x58); s5h1420_writereg(state, Loop05, 0x6b); - if (p->u.qpsk.symbol_rate >= 8000000) + if (p->symbol_rate >= 8000000) s5h1420_writereg(state, Post01, (0 << 6) | 0x10); - else if (p->u.qpsk.symbol_rate >= 4000000) + else if (p->symbol_rate >= 4000000) s5h1420_writereg(state, Post01, (1 << 6) | 0x10); else s5h1420_writereg(state, Post01, (3 << 6) | 0x10); @@ -744,7 +743,7 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, /* set tuner PLL */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); s5h1420_setfreqoffset(state, 0); @@ -757,8 +756,8 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, /* start QPSK */ s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1); - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; + state->fec_inner = p->fec_inner; + state->symbol_rate = p->symbol_rate; state->postlocked = 0; state->tunedfreq = p->frequency; @@ -766,15 +765,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, return 0; } -static int s5h1420_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int s5h1420_get_frontend(struct dvb_frontend* fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s5h1420_state* state = fe->demodulator_priv; p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); p->inversion = s5h1420_getinversion(state); - p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); - p->u.qpsk.fec_inner = s5h1420_getfec(state); + p->symbol_rate = s5h1420_getsymbolrate(state); + p->fec_inner = s5h1420_getfec(state); return 0; } @@ -782,29 +781,30 @@ static int s5h1420_get_frontend(struct dvb_frontend* fe, static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + if (p->symbol_rate > 20000000) { fesettings->min_delay_ms = 50; fesettings->step_size = 2000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + } else if (p->symbol_rate > 12000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1500; fesettings->max_drift = 9000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + } else if (p->symbol_rate > 8000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + } else if (p->symbol_rate > 4000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 500; fesettings->max_drift = 7000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + } else if (p->symbol_rate > 2000000) { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = (p->symbol_rate / 8000); fesettings->max_drift = 14 * fesettings->step_size; } else { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = (p->symbol_rate / 8000); fesettings->max_drift = 18 * fesettings->step_size; } @@ -937,10 +937,9 @@ error: EXPORT_SYMBOL(s5h1420_attach); static struct dvb_frontend_ops s5h1420_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c index 0c6dcb90d168..8352ce1c9556 100644 --- a/drivers/media/dvb/frontends/s5h1432.c +++ b/drivers/media/dvb/frontends/s5h1432.c @@ -178,9 +178,9 @@ static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz) } /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int s5h1432_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s5h1432_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 dvb_bandwidth = 8; struct s5h1432_state *state = fe->demodulator_priv; @@ -188,26 +188,26 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe, /*current_frequency = p->frequency; */ /*state->current_frequency = p->frequency; */ } else { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); msleep(300); s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: dvb_bandwidth = 6; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_7_MHZ: + case 7000000: dvb_bandwidth = 7; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_8_MHZ: + case 8000000: dvb_bandwidth = 8; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; default: return 0; } - /*fe->ops.tuner_ops.set_params(fe, p); */ + /*fe->ops.tuner_ops.set_params(fe); */ /*Soft Reset chip*/ msleep(30); s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); @@ -215,23 +215,23 @@ static int s5h1432_set_frontend(struct dvb_frontend *fe, s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b); s5h1432_set_channel_bandwidth(fe, dvb_bandwidth); - switch (p->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: dvb_bandwidth = 6; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_7_MHZ: + case 7000000: dvb_bandwidth = 7; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; - case BANDWIDTH_8_MHZ: + case 8000000: dvb_bandwidth = 8; s5h1432_set_IF(fe, IF_FREQ_4_MHZ); break; default: return 0; } - /*fe->ops.tuner_ops.set_params(fe,p); */ + /*fe->ops.tuner_ops.set_params(fe); */ /*Soft Reset chip*/ msleep(30); s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a); @@ -329,12 +329,6 @@ static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber) return 0; } -static int s5h1432_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - return 0; -} - static int s5h1432_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { @@ -381,10 +375,9 @@ error: EXPORT_SYMBOL(s5h1432_attach); static struct dvb_frontend_ops s5h1432_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Samsung s5h1432 DVB-T Frontend", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, @@ -397,7 +390,6 @@ static struct dvb_frontend_ops s5h1432_ops = { .init = s5h1432_init, .sleep = s5h1432_sleep, .set_frontend = s5h1432_set_frontend, - .get_frontend = s5h1432_get_frontend, .get_tune_settings = s5h1432_get_tune_settings, .read_status = s5h1432_read_status, .read_ber = s5h1432_read_ber, diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb/frontends/s921.c index ca0103d5f148..cd2288c07147 100644 --- a/drivers/media/dvb/frontends/s921.c +++ b/drivers/media/dvb/frontends/s921.c @@ -262,9 +262,9 @@ static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg) s921_i2c_writeregdata(state, state->config->demod_address, \ regdata, ARRAY_SIZE(regdata)) -static int s921_pll_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s921_pll_tune(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s921_state *state = fe->demodulator_priv; int band, rc, i; unsigned long f_offset; @@ -414,9 +414,9 @@ static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; } -static int s921_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s921_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s921_state *state = fe->demodulator_priv; int rc; @@ -424,7 +424,7 @@ static int s921_set_frontend(struct dvb_frontend *fe, /* FIXME: We don't know how to use non-auto mode */ - rc = s921_pll_tune(fe, p); + rc = s921_pll_tune(fe); if (rc < 0) return rc; @@ -433,19 +433,20 @@ static int s921_set_frontend(struct dvb_frontend *fe, return 0; } -static int s921_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int s921_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct s921_state *state = fe->demodulator_priv; /* FIXME: Probably it is possible to get it from regs f1 and f2 */ p->frequency = state->currentfreq; + p->delivery_system = SYS_ISDBT; return 0; } static int s921_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) @@ -454,8 +455,8 @@ static int s921_tune(struct dvb_frontend *fe, dprintk("\n"); - if (params != NULL) - rc = s921_set_frontend(fe, params); + if (re_tune) + rc = s921_set_frontend(fe); if (!(mode_flags & FE_TUNE_MODE_ONESHOT)) s921_read_status(fe, status); @@ -510,10 +511,10 @@ rcor: EXPORT_SYMBOL(s921_attach); static struct dvb_frontend_ops s921_ops = { + .delsys = { SYS_ISDBT }, /* Use dib8000 values per default */ .info = { .name = "Sharp S921", - .type = FE_OFDM, .frequency_min = 470000000, /* * Max should be 770MHz instead, according with Sharp docs, diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c index 4b0c99a08a85..a68a64800df7 100644 --- a/drivers/media/dvb/frontends/si21xx.c +++ b/drivers/media/dvb/frontends/si21xx.c @@ -690,20 +690,7 @@ static int si21xx_setacquire(struct dvb_frontend *fe, int symbrate, return status; } -static int si21xx_set_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int si21xx_get_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int si21xx_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *dfp) +static int si21xx_set_frontend(struct dvb_frontend *fe) { struct si21xx_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -877,10 +864,9 @@ static void si21xx_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops si21xx_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "SL SI21XX DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ @@ -908,8 +894,6 @@ static struct dvb_frontend_ops si21xx_ops = { .set_tone = si21xx_set_tone, .set_voltage = si21xx_set_voltage, - .set_property = si21xx_set_property, - .get_property = si21xx_get_property, .set_frontend = si21xx_set_frontend, }; diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index b85eb60a893e..e37274c8f14e 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -168,13 +168,13 @@ static int sp8870_read_data_valid_signal(struct sp8870_state* state) return (sp8870_readreg(state, 0x0D02) > 0); } -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) { int known_parameters = 1; *reg0xc05 = 0x000; - switch (p->u.ofdm.constellation) { + switch (p->modulation) { case QPSK: break; case QAM_16: @@ -190,7 +190,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -209,7 +209,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.code_rate_HP) { + switch (p->code_rate_HP) { case FEC_1_2: break; case FEC_2_3: @@ -245,9 +245,9 @@ static int sp8870_wake_up(struct sp8870_state* state) return sp8870_writereg(state, 0xC18, 0x00D); } -static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int sp8870_set_frontend_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct sp8870_state* state = fe->demodulator_priv; int err; u16 reg0xc05; @@ -260,7 +260,7 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, // set tuner parameters if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -277,15 +277,15 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, sp8870_writereg(state, 0x030A, 0x0000); // filter for 6/7/8 Mhz channel - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + if (p->bandwidth_hz == 6000000) sp8870_writereg(state, 0x0311, 0x0002); - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + else if (p->bandwidth_hz == 7000000) sp8870_writereg(state, 0x0311, 0x0001); else sp8870_writereg(state, 0x0311, 0x0000); // scan order: 2k first = 0x0000, 8k first = 0x0001 - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + if (p->transmission_mode == TRANSMISSION_MODE_2K) sp8870_writereg(state, 0x0338, 0x0000); else sp8870_writereg(state, 0x0338, 0x0001); @@ -459,8 +459,9 @@ static int lockups; /* only for debugging: counter for channel switches */ static int switches; -static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int sp8870_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct sp8870_state* state = fe->demodulator_priv; /* @@ -479,7 +480,8 @@ static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_par for (trials = 1; trials <= MAXTRIALS; trials++) { - if ((err = sp8870_set_frontend_parameters(fe, p))) + err = sp8870_set_frontend_parameters(fe); + if (err) return err; for (check_count = 0; check_count < MAXCHECKS; check_count++) { @@ -579,10 +581,9 @@ error: } static struct dvb_frontend_ops sp8870_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Spase SP8870 DVB-T", - .type = FE_OFDM, .frequency_min = 470000000, .frequency_max = 860000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 4a7c3d842608..f4096ccb226e 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -209,13 +209,13 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware return 0; }; -static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) { int known_parameters = 1; *reg0xc05 = 0x000; - switch (p->u.ofdm.constellation) { + switch (p->modulation) { case QPSK: break; case QAM_16: @@ -231,7 +231,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.hierarchy_information) { + switch (p->hierarchy) { case HIERARCHY_NONE: break; case HIERARCHY_1: @@ -250,7 +250,7 @@ static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) return -EINVAL; }; - switch (p->u.ofdm.code_rate_HP) { + switch (p->code_rate_HP) { case FEC_1_2: break; case FEC_2_3: @@ -303,17 +303,30 @@ static void divide (int n, int d, int *quotient_i, int *quotient_f) } static void sp887x_correct_offsets (struct sp887x_state* state, - struct dvb_frontend_parameters *p, + struct dtv_frontend_properties *p, int actual_freq) { static const u32 srate_correction [] = { 1879617, 4544878, 8098561 }; - int bw_index = p->u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + int bw_index; int freq_offset = actual_freq - p->frequency; int sysclock = 61003; //[kHz] int ifreq = 36000000; int freq; int frequency_shift; + switch (p->bandwidth_hz) { + default: + case 8000000: + bw_index = 0; + break; + case 7000000: + bw_index = 1; + break; + case 6000000: + bw_index = 2; + break; + } + if (p->inversion == INVERSION_ON) freq = ifreq - freq_offset; else @@ -333,17 +346,17 @@ static void sp887x_correct_offsets (struct sp887x_state* state, sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); } -static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, - struct dvb_frontend_parameters *p) +static int sp887x_setup_frontend_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct sp887x_state* state = fe->demodulator_priv; unsigned actual_freq; int err; u16 val, reg0xc05; - if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && - p->u.ofdm.bandwidth != BANDWIDTH_7_MHZ && - p->u.ofdm.bandwidth != BANDWIDTH_6_MHZ) + if (p->bandwidth_hz != 8000000 && + p->bandwidth_hz != 7000000 && + p->bandwidth_hz != 6000000) return -EINVAL; if ((err = configure_reg0xc05(p, ®0xc05))) @@ -353,7 +366,7 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, /* setup the PLL */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (fe->ops.tuner_ops.get_frequency) { @@ -369,9 +382,9 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, sp887x_correct_offsets(state, p, actual_freq); /* filter for 6/7/8 Mhz channel */ - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + if (p->bandwidth_hz == 6000000) val = 2; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + else if (p->bandwidth_hz == 7000000) val = 1; else val = 0; @@ -379,16 +392,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, sp887x_writereg(state, 0x311, val); /* scan order: 2k first = 0, 8k first = 1 */ - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + if (p->transmission_mode == TRANSMISSION_MODE_2K) sp887x_writereg(state, 0x338, 0x000); else sp887x_writereg(state, 0x338, 0x001); sp887x_writereg(state, 0xc05, reg0xc05); - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + if (p->bandwidth_hz == 6000000) val = 2 << 3; - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + else if (p->bandwidth_hz == 7000000) val = 3 << 3; else val = 0 << 3; @@ -579,10 +592,9 @@ error: } static struct dvb_frontend_ops sp887x_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Spase SP887x DVB-T", - .type = FE_OFDM, .frequency_min = 50500000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c index 8408ef877b4b..38565beafe23 100644 --- a/drivers/media/dvb/frontends/stb0899_drv.c +++ b/drivers/media/dvb/frontends/stb0899_drv.c @@ -1431,7 +1431,7 @@ static void stb0899_set_iterations(struct stb0899_state *state) stb0899_write_s2reg(state, STB0899_S2FEC, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg); } -static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static enum dvbfe_search stb0899_search(struct dvb_frontend *fe) { struct stb0899_state *state = fe->demodulator_priv; struct stb0899_params *i_params = &state->params; @@ -1441,8 +1441,8 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron u32 SearchRange, gain; - i_params->freq = p->frequency; - i_params->srate = p->u.qpsk.symbol_rate; + i_params->freq = props->frequency; + i_params->srate = props->symbol_rate; state->delsys = props->delivery_system; dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys); @@ -1568,34 +1568,15 @@ static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_fron return DVBFE_ALGO_SEARCH_ERROR; } -/* - * stb0899_track - * periodically check the signal level against a specified - * threshold level and perform derotator centering. - * called once we have a lock from a successful search - * event. - * - * Will be called periodically called to maintain the - * lock. - * - * Will be used to get parameters as well as info from - * the decoded baseband header - * - * Once a new lock has established, the internal state - * frequency (internal->freq) is updated - */ -static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) -{ - return 0; -} -static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int stb0899_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stb0899_state *state = fe->demodulator_priv; struct stb0899_internal *internal = &state->internal; dprintk(state->verbose, FE_DEBUG, 1, "Get params"); - p->u.qpsk.symbol_rate = internal->srate; + p->symbol_rate = internal->srate; return 0; } @@ -1606,10 +1587,9 @@ static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) } static struct dvb_frontend_ops stb0899_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STB0899 Multistandard", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 0, @@ -1632,8 +1612,7 @@ static struct dvb_frontend_ops stb0899_ops = { .get_frontend_algo = stb0899_frontend_algo, .search = stb0899_search, - .track = stb0899_track, - .get_frontend = stb0899_get_frontend, + .get_frontend = stb0899_get_frontend, .read_status = stb0899_read_status, diff --git a/drivers/media/dvb/frontends/stb6000.c b/drivers/media/dvb/frontends/stb6000.c index ed699647050e..a0c3c526b132 100644 --- a/drivers/media/dvb/frontends/stb6000.c +++ b/drivers/media/dvb/frontends/stb6000.c @@ -75,9 +75,9 @@ static int stb6000_sleep(struct dvb_frontend *fe) return (ret == 1) ? 0 : ret; } -static int stb6000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int stb6000_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stb6000_priv *priv = fe->tuner_priv; unsigned int n, m; int ret; @@ -93,8 +93,8 @@ static int stb6000_set_params(struct dvb_frontend *fe, dprintk("%s:\n", __func__); - freq_mhz = params->frequency / 1000; - bandwidth = params->u.qpsk.symbol_rate / 1000000; + freq_mhz = p->frequency / 1000; + bandwidth = p->symbol_rate / 1000000; if (bandwidth > 31) bandwidth = 31; diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index bc1a8af4f6e1..def88abb30bf 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c @@ -327,7 +327,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) int rc; const struct stb6100_lkup *ptr; struct stb6100_state *state = fe->tuner_priv; - struct dvb_frontend_parameters p; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 srate = 0, fvco, nint, nfrac; u8 regs[STB6100_NUMREGS]; @@ -337,9 +337,9 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) if (fe->ops.get_frontend) { dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters"); - fe->ops.get_frontend(fe, &p); + fe->ops.get_frontend(fe); } - srate = p.u.qpsk.symbol_rate; + srate = p->symbol_rate; /* Set up tuner cleanly, LPF calibration on */ rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK); diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index 0aa3962ff18b..fb5548a82208 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c @@ -452,14 +452,7 @@ static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) return 0; } -static int stv0288_get_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - -static int stv0288_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *dfp) +static int stv0288_set_frontend(struct dvb_frontend *fe) { struct stv0288_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -481,10 +474,8 @@ static int stv0288_set_frontend(struct dvb_frontend *fe, state->config->set_ts_params(fe, 0); /* only frequency & symbol_rate are used for tuner*/ - dfp->frequency = c->frequency; - dfp->u.qpsk.symbol_rate = c->symbol_rate; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, dfp); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -545,10 +536,9 @@ static void stv0288_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops stv0288_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "ST STV0288 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, /* kHz for QPSK frontends */ @@ -578,7 +568,6 @@ static struct dvb_frontend_ops stv0288_ops = { .set_voltage = stv0288_set_voltage, .set_property = stv0288_set_property, - .get_property = stv0288_get_property, .set_frontend = stv0288_set_frontend, }; diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 84d88f33275e..85c157a1fe5e 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -404,8 +404,9 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) return 0; } -static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int stv0297_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0297_state *state = fe->demodulator_priv; int u_threshold; int initial_u; @@ -417,7 +418,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par unsigned long timeout; fe_spectral_inversion_t inversion; - switch (p->u.qam.modulation) { + switch (p->modulation) { case QAM_16: case QAM_32: case QAM_64: @@ -455,7 +456,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_init(fe); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -519,16 +520,16 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); /* set parameters */ - stv0297_set_qam(state, p->u.qam.modulation); - stv0297_set_symbolrate(state, p->u.qam.symbol_rate / 1000); - stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000); + stv0297_set_qam(state, p->modulation); + stv0297_set_symbolrate(state, p->symbol_rate / 1000); + stv0297_set_sweeprate(state, sweeprate, p->symbol_rate / 1000); stv0297_set_carrieroffset(state, carrieroffset); stv0297_set_inversion(state, inversion); /* kick off lock */ /* Disable corner detection for higher QAMs */ - if (p->u.qam.modulation == QAM_128 || - p->u.qam.modulation == QAM_256) + if (p->modulation == QAM_128 || + p->modulation == QAM_256) stv0297_writereg_mask(state, 0x88, 0x08, 0x00); else stv0297_writereg_mask(state, 0x88, 0x08, 0x08); @@ -613,8 +614,9 @@ timeout: return 0; } -static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static int stv0297_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0297_state *state = fe->demodulator_priv; int reg_00, reg_83; @@ -625,24 +627,24 @@ static int stv0297_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; if (state->config->invert) p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; - p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000; - p->u.qam.fec_inner = FEC_NONE; + p->symbol_rate = stv0297_get_symbolrate(state) * 1000; + p->fec_inner = FEC_NONE; switch ((reg_00 >> 4) & 0x7) { case 0: - p->u.qam.modulation = QAM_16; + p->modulation = QAM_16; break; case 1: - p->u.qam.modulation = QAM_32; + p->modulation = QAM_32; break; case 2: - p->u.qam.modulation = QAM_128; + p->modulation = QAM_128; break; case 3: - p->u.qam.modulation = QAM_256; + p->modulation = QAM_256; break; case 4: - p->u.qam.modulation = QAM_64; + p->modulation = QAM_64; break; } @@ -688,10 +690,9 @@ error: } static struct dvb_frontend_ops stv0297_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0297 DVB-C", - .type = FE_QAM, .frequency_min = 47000000, .frequency_max = 862000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 42684bec8883..057b5f8effc0 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -559,8 +559,9 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +static int stv0299_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0299_state* state = fe->demodulator_priv; int invval = 0; @@ -579,24 +580,25 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - stv0299_set_FEC (state, p->u.qpsk.fec_inner); - stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); + stv0299_set_FEC(state, p->fec_inner); + stv0299_set_symbolrate(fe, p->symbol_rate); stv0299_writeregI(state, 0x22, 0x00); stv0299_writeregI(state, 0x23, 0x00); state->tuner_frequency = p->frequency; - state->fec_inner = p->u.qpsk.fec_inner; - state->symbol_rate = p->u.qpsk.symbol_rate; + state->fec_inner = p->fec_inner; + state->symbol_rate = p->symbol_rate; return 0; } -static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +static int stv0299_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0299_state* state = fe->demodulator_priv; s32 derot_freq; int invval; @@ -614,8 +616,8 @@ static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->config->invert) invval = (~invval) & 1; p->inversion = invval ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = stv0299_get_fec (state); - p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); + p->fec_inner = stv0299_get_fec(state); + p->symbol_rate = stv0299_get_symbolrate(state); return 0; } @@ -646,14 +648,15 @@ static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { struct stv0299_state* state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; fesettings->min_delay_ms = state->config->min_delay_ms; - if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; + if (p->symbol_rate < 10000000) { + fesettings->step_size = p->symbol_rate / 32000; fesettings->max_drift = 5000; } else { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; - fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; + fesettings->step_size = p->symbol_rate / 16000; + fesettings->max_drift = p->symbol_rate / 2000; } return 0; } @@ -705,10 +708,9 @@ error: } static struct dvb_frontend_ops stv0299_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "ST STV0299 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index e57ab53e2e27..fdd20c7737b5 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -1577,9 +1577,9 @@ int stv0367ter_init(struct dvb_frontend *fe) return 0; } -static int stv0367ter_algo(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367ter_algo(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; int offset = 0, tempo = 0; @@ -1591,7 +1591,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe, dprintk("%s:\n", __func__); - ter_state->frequency = param->frequency; + ter_state->frequency = p->frequency; ter_state->force = FE_TER_FORCENONE + stv0367_readbits(state, F367TER_FORCE) * 2; ter_state->if_iq_mode = state->config->if_iq_mode; @@ -1620,7 +1620,7 @@ static int stv0367ter_algo(struct dvb_frontend *fe, usleep_range(5000, 7000); - switch (param->inversion) { + switch (p->inversion) { case INVERSION_AUTO: default: dprintk("%s: inversion AUTO\n", __func__); @@ -1636,10 +1636,10 @@ static int stv0367ter_algo(struct dvb_frontend *fe, case INVERSION_OFF: if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) stv0367_writebits(state, F367TER_IQ_INVERT, - param->inversion); + p->inversion); else stv0367_writebits(state, F367TER_INV_SPECTR, - param->inversion); + p->inversion); break; } @@ -1806,10 +1806,9 @@ static int stv0367ter_algo(struct dvb_frontend *fe, return 0; } -static int stv0367ter_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367ter_set_frontend(struct dvb_frontend *fe) { - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; @@ -1822,12 +1821,12 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - switch (op->transmission_mode) { + switch (p->transmission_mode) { default: case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_2K: @@ -1841,34 +1840,34 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe, break; } - switch (op->guard_interval) { + switch (p->guard_interval) { default: case GUARD_INTERVAL_1_32: case GUARD_INTERVAL_1_16: case GUARD_INTERVAL_1_8: case GUARD_INTERVAL_1_4: - ter_state->guard = op->guard_interval; + ter_state->guard = p->guard_interval; break; case GUARD_INTERVAL_AUTO: ter_state->guard = GUARD_INTERVAL_1_32; break; } - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: ter_state->bw = FE_TER_CHAN_BW_6M; break; - case BANDWIDTH_7_MHZ: + case 7000000: ter_state->bw = FE_TER_CHAN_BW_7M; break; - case BANDWIDTH_8_MHZ: + case 8000000: default: ter_state->bw = FE_TER_CHAN_BW_8M; } ter_state->hierarchy = FE_TER_HIER_NONE; - switch (param->inversion) { + switch (p->inversion) { case INVERSION_OFF: case INVERSION_ON: num_trials = 1; @@ -1885,14 +1884,14 @@ static int stv0367ter_set_frontend(struct dvb_frontend *fe, while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) { if (!ter_state->first_lock) { - if (param->inversion == INVERSION_AUTO) + if (p->inversion == INVERSION_AUTO) ter_state->sense = SenseTrials[index]; } - stv0367ter_algo(fe,/* &pLook, result,*/ param); + stv0367ter_algo(fe); if ((ter_state->state == FE_TER_LOCKOK) && - (param->inversion == INVERSION_AUTO) && + (p->inversion == INVERSION_AUTO) && (index == 1)) { /* invert spectrum sense */ SenseTrials[index] = SenseTrials[0]; @@ -1927,50 +1926,48 @@ static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int stv0367ter_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367ter_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; int error = 0; enum stv0367_ter_mode mode; int constell = 0,/* snr = 0,*/ Data = 0; - param->frequency = stv0367_get_tuner_freq(fe); - if ((int)param->frequency < 0) - param->frequency = c->frequency; + p->frequency = stv0367_get_tuner_freq(fe); + if ((int)p->frequency < 0) + p->frequency = -p->frequency; constell = stv0367_readbits(state, F367TER_TPS_CONST); if (constell == 0) - op->constellation = QPSK; + p->modulation = QPSK; else if (constell == 1) - op->constellation = QAM_16; + p->modulation = QAM_16; else - op->constellation = QAM_64; + p->modulation = QAM_64; - param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); + p->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); /* Get the Hierarchical mode */ Data = stv0367_readbits(state, F367TER_TPS_HIERMODE); switch (Data) { case 0: - op->hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - op->hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - op->hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - op->hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; default: - op->hierarchy_information = HIERARCHY_AUTO; + p->hierarchy = HIERARCHY_AUTO; break; /* error */ } @@ -1982,22 +1979,22 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, switch (Data) { case 0: - op->code_rate_HP = FEC_1_2; + p->code_rate_HP = FEC_1_2; break; case 1: - op->code_rate_HP = FEC_2_3; + p->code_rate_HP = FEC_2_3; break; case 2: - op->code_rate_HP = FEC_3_4; + p->code_rate_HP = FEC_3_4; break; case 3: - op->code_rate_HP = FEC_5_6; + p->code_rate_HP = FEC_5_6; break; case 4: - op->code_rate_HP = FEC_7_8; + p->code_rate_HP = FEC_7_8; break; default: - op->code_rate_HP = FEC_AUTO; + p->code_rate_HP = FEC_AUTO; break; /* error */ } @@ -2005,19 +2002,19 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, switch (mode) { case FE_TER_MODE_2K: - op->transmission_mode = TRANSMISSION_MODE_2K; + p->transmission_mode = TRANSMISSION_MODE_2K; break; /* case FE_TER_MODE_4K: - op->transmission_mode = TRANSMISSION_MODE_4K; + p->transmission_mode = TRANSMISSION_MODE_4K; break;*/ case FE_TER_MODE_8K: - op->transmission_mode = TRANSMISSION_MODE_8K; + p->transmission_mode = TRANSMISSION_MODE_8K; break; default: - op->transmission_mode = TRANSMISSION_MODE_AUTO; + p->transmission_mode = TRANSMISSION_MODE_AUTO; } - op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); + p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); return error; } @@ -2265,9 +2262,9 @@ static void stv0367_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops stv0367ter_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "ST STV0367 DVB-T", - .type = FE_OFDM, .frequency_min = 47000000, .frequency_max = 862000000, .frequency_stepsize = 15625, @@ -2822,9 +2819,8 @@ int stv0367cab_init(struct dvb_frontend *fe) } static enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, - struct dvb_frontend_parameters *param) + struct dtv_frontend_properties *p) { - struct dvb_qam_parameters *op = ¶m->u.qam; struct stv0367cab_state *cab_state = state->cab_state; enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC; u32 QAMFEC_Lock, QAM_Lock, u32_tmp, @@ -2839,7 +2835,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, /* A max lock time of 25 ms is allowed for delayed AGC */ AGCTimeOut = 25; /* 100000 symbols needed by the TRL as a maximum value */ - TRLTimeOut = 100000000 / op->symbol_rate; + TRLTimeOut = 100000000 / p->symbol_rate; /* CRLSymbols is the needed number of symbols to achieve a lock within [-4%, +4%] of the symbol rate. CRL timeout is calculated @@ -2849,7 +2845,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, A characterization must be performed with these echoes to get new timeout values. */ - switch (op->modulation) { + switch (p->modulation) { case QAM_16: CRLSymbols = 150000; EQLTimeOut = 100; @@ -2883,9 +2879,9 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, } else #endif CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) / - (op->symbol_rate / 1000); + (p->symbol_rate / 1000); - CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate; + CRLTimeOut = (1000 * CRLTimeOut) / p->symbol_rate; /* Timeouts below 50ms are coerced */ if (CRLTimeOut < 50) CRLTimeOut = 50; @@ -2915,7 +2911,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, stv0367cab_set_derot_freq(state, cab_state->adc_clk, (1000 * (s32)state->config->if_khz + cab_state->derot_offset)); /* Disable the Allpass Filter when the symbol rate is out of range */ - if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) { + if ((p->symbol_rate > 10800000) | (p->symbol_rate < 1800000)) { stv0367_writebits(state, F367CAB_ADJ_EN, 0); stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); } @@ -2999,7 +2995,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, if (QAMFEC_Lock) { signalType = FE_CAB_DATAOK; - cab_state->modulation = op->modulation; + cab_state->modulation = p->modulation; cab_state->spect_inv = stv0367_readbits(state, F367CAB_QUAD_INV); #if 0 @@ -3081,20 +3077,19 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, return signalType; } -static int stv0367cab_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367cab_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367cab_state *cab_state = state->cab_state; - struct dvb_qam_parameters *op = ¶m->u.qam; enum stv0367cab_mod QAMSize = 0; dprintk("%s: freq = %d, srate = %d\n", __func__, - param->frequency, op->symbol_rate); + p->frequency, p->symbol_rate); cab_state->derot_offset = 0; - switch (op->modulation) { + switch (p->modulation) { case QAM_16: QAMSize = FE_CAB_MOD_QAM16; break; @@ -3120,77 +3115,76 @@ static int stv0367cab_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } stv0367cab_SetQamSize( state, - op->symbol_rate, + p->symbol_rate, QAMSize); stv0367cab_set_srate(state, cab_state->adc_clk, cab_state->mclk, - op->symbol_rate, + p->symbol_rate, QAMSize); /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */ - cab_state->state = stv0367cab_algo(state, param); + cab_state->state = stv0367cab_algo(state, p); return 0; } -static int stv0367cab_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int stv0367cab_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367cab_state *cab_state = state->cab_state; - struct dvb_qam_parameters *op = ¶m->u.qam; enum stv0367cab_mod QAMSize; dprintk("%s:\n", __func__); - op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); + p->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); switch (QAMSize) { case FE_CAB_MOD_QAM16: - op->modulation = QAM_16; + p->modulation = QAM_16; break; case FE_CAB_MOD_QAM32: - op->modulation = QAM_32; + p->modulation = QAM_32; break; case FE_CAB_MOD_QAM64: - op->modulation = QAM_64; + p->modulation = QAM_64; break; case FE_CAB_MOD_QAM128: - op->modulation = QAM_128; + p->modulation = QAM_128; break; case QAM_256: - op->modulation = QAM_256; + p->modulation = QAM_256; break; default: break; } - param->frequency = stv0367_get_tuner_freq(fe); + p->frequency = stv0367_get_tuner_freq(fe); - dprintk("%s: tuner frequency = %d\n", __func__, param->frequency); + dprintk("%s: tuner frequency = %d\n", __func__, p->frequency); if (state->config->if_khz == 0) { - param->frequency += + p->frequency += (stv0367cab_get_derot_freq(state, cab_state->adc_clk) - cab_state->adc_clk / 4000); return 0; } if (state->config->if_khz > cab_state->adc_clk / 1000) - param->frequency += (state->config->if_khz + p->frequency += (state->config->if_khz - stv0367cab_get_derot_freq(state, cab_state->adc_clk) - cab_state->adc_clk / 1000); else - param->frequency += (state->config->if_khz + p->frequency += (state->config->if_khz - stv0367cab_get_derot_freq(state, cab_state->adc_clk)); return 0; @@ -3386,9 +3380,9 @@ static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks) }; static struct dvb_frontend_ops stv0367cab_ops = { + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0367 DVB-C", - .type = FE_QAM, .frequency_min = 47000000, .frequency_max = 862000000, .frequency_stepsize = 62500, diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 0ca316d6fffa..7f1badaf0d03 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -973,22 +973,6 @@ static enum dvbfe_algo stv0900_frontend_algo(struct dvb_frontend *fe) return DVBFE_ALGO_CUSTOM; } -static int stb0900_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - - return 0; -} - -static int stb0900_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - dprintk("%s(..)\n", __func__); - - return 0; -} - void stv0900_start_search(struct stv0900_internal *intp, enum fe_stv0900_demod_num demod) { @@ -1574,8 +1558,7 @@ static int stv0900_status(struct stv0900_internal *intp, return locked; } -static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static enum dvbfe_search stv0900_search(struct dvb_frontend *fe) { struct stv0900_state *state = fe->demodulator_priv; struct stv0900_internal *intp = state->internal; @@ -1675,12 +1658,6 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status) return 0; } -static int stv0900_track(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - return 0; -} - static int stv0900_stop_ts(struct dvb_frontend *fe, int stop_ts) { @@ -1866,24 +1843,23 @@ static int stv0900_sleep(struct dvb_frontend *fe) return 0; } -static int stv0900_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int stv0900_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0900_state *state = fe->demodulator_priv; struct stv0900_internal *intp = state->internal; enum fe_stv0900_demod_num demod = state->demod; struct stv0900_signal_info p_result = intp->result[demod]; p->frequency = p_result.locked ? p_result.frequency : 0; - p->u.qpsk.symbol_rate = p_result.locked ? p_result.symbol_rate : 0; + p->symbol_rate = p_result.locked ? p_result.symbol_rate : 0; return 0; } static struct dvb_frontend_ops stv0900_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV0900 frontend", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, @@ -1907,10 +1883,7 @@ static struct dvb_frontend_ops stv0900_ops = { .diseqc_send_burst = stv0900_send_burst, .diseqc_recv_slave_reply = stv0900_recv_slave_reply, .set_tone = stv0900_set_tone, - .set_property = stb0900_set_property, - .get_property = stb0900_get_property, .search = stv0900_search, - .track = stv0900_track, .read_status = stv0900_read_status, .read_ber = stv0900_read_ber, .read_signal_strength = stv0900_read_signal_strength, diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index ebda41936b90..4aef1877ed42 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3427,17 +3427,17 @@ err: return -1; } -static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +static enum dvbfe_search stv090x_search(struct dvb_frontend *fe) { struct stv090x_state *state = fe->demodulator_priv; struct dtv_frontend_properties *props = &fe->dtv_property_cache; - if (p->frequency == 0) + if (props->frequency == 0) return DVBFE_ALGO_SEARCH_INVALID; state->delsys = props->delivery_system; - state->frequency = p->frequency; - state->srate = p->u.qpsk.symbol_rate; + state->frequency = props->frequency; + state->srate = props->symbol_rate; state->search_mode = STV090x_SEARCH_AUTO; state->algo = STV090x_COLD_SEARCH; state->fec = STV090x_PRERR; @@ -4712,10 +4712,9 @@ int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, EXPORT_SYMBOL(stv090x_set_gpio); static struct dvb_frontend_ops stv090x_ops = { - + .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV090x Multistandard", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 0, @@ -4743,7 +4742,7 @@ static struct dvb_frontend_ops stv090x_ops = { .read_status = stv090x_read_status, .read_ber = stv090x_read_per, .read_signal_strength = stv090x_read_signal_strength, - .read_snr = stv090x_read_cnr + .read_snr = stv090x_read_cnr, }; diff --git a/drivers/media/dvb/frontends/stv6110.c b/drivers/media/dvb/frontends/stv6110.c index 2dca7c8e5148..20b5fa92c53e 100644 --- a/drivers/media/dvb/frontends/stv6110.c +++ b/drivers/media/dvb/frontends/stv6110.c @@ -347,8 +347,7 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency) return 0; } -static int stv6110_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int stv6110_set_params(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 bandwidth = carrier_width(c->symbol_rate, c->rolloff); diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 6ca533ea0f0e..1bff7f457e19 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -224,47 +224,86 @@ static int tda10021_init (struct dvb_frontend *fe) return 0; } -static int tda10021_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +struct qam_params { + u8 conf, agcref, lthr, mseth, aref; +}; + +static int tda10021_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + unsigned qam = c->modulation; + bool is_annex_c; + u32 reg0x3d; struct tda10021_state* state = fe->demodulator_priv; + static const struct qam_params qam_params[] = { + /* Modulation Conf AGCref LTHR MSETH AREF */ + [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 }, + [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 }, + [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 }, + [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a }, + [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e }, + [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b }, + }; + + switch (delsys) { + case SYS_DVBC_ANNEX_A: + is_annex_c = false; + break; + case SYS_DVBC_ANNEX_C: + is_annex_c = true; + break; + default: + return -EINVAL; + } - //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 - //CONF - static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; - //AGCREF value - static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; - //LTHR value - static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; - //MSETH - static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; - //AREF - static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; - - int qam = p->u.qam.modulation; - - if (qam < 0 || qam > 5) + /* + * gcc optimizes the code bellow the same way as it would code: + * "if (qam > 5) return -EINVAL;" + * Yet, the code is clearer, as it shows what QAM standards are + * supported by the driver, and avoids the usage of magic numbers on + * it. + */ + switch (qam) { + case QPSK: + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + break; + default: return -EINVAL; + } - if (p->inversion != INVERSION_ON && p->inversion != INVERSION_OFF) + if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF) return -EINVAL; - //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); + /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - tda10021_set_symbolrate (state, p->u.qam.symbol_rate); - _tda10021_writereg (state, 0x34, state->pwm); - - _tda10021_writereg (state, 0x01, reg0x01[qam]); - _tda10021_writereg (state, 0x05, reg0x05[qam]); - _tda10021_writereg (state, 0x08, reg0x08[qam]); - _tda10021_writereg (state, 0x09, reg0x09[qam]); - - tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); + tda10021_set_symbolrate(state, c->symbol_rate); + _tda10021_writereg(state, 0x34, state->pwm); + + _tda10021_writereg(state, 0x01, qam_params[qam].agcref); + _tda10021_writereg(state, 0x05, qam_params[qam].lthr); + _tda10021_writereg(state, 0x08, qam_params[qam].mseth); + _tda10021_writereg(state, 0x09, qam_params[qam].aref); + + /* + * Bit 0 == 0 means roll-off = 0.15 (Annex A) + * == 1 means roll-off = 0.13 (Annex C) + */ + reg0x3d = tda10021_readreg (state, 0x3d); + if (is_annex_c) + _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d); + else + _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d); + tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion); return 0; } @@ -347,8 +386,9 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda10021_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10021_state* state = fe->demodulator_priv; int sync; s8 afc = 0; @@ -360,17 +400,17 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); + -((s32)p->symbol_rate * afc) >> 10); } p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF; - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; - p->u.qam.fec_inner = FEC_NONE; + p->fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + p->frequency -= ((s32)p->symbol_rate * afc) >> 10; return 0; } @@ -444,10 +484,9 @@ error: } static struct dvb_frontend_ops tda10021_ops = { - + .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, .info = { .name = "Philips TDA10021 DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c index a3c34eecdee9..ca1e0d54b69a 100644 --- a/drivers/media/dvb/frontends/tda10023.c +++ b/drivers/media/dvb/frontends/tda10023.c @@ -298,42 +298,80 @@ static int tda10023_init (struct dvb_frontend *fe) return 0; } -static int tda10023_set_parameters (struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +struct qam_params { + u8 qam, lockthr, mseth, aref, agcrefnyq, eragnyq_thd; +}; + +static int tda10023_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 delsys = c->delivery_system; + unsigned qam = c->modulation; + bool is_annex_c; struct tda10023_state* state = fe->demodulator_priv; - - static int qamvals[6][6] = { - // QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD - { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, // 4 QAM - { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, // 16 QAM - { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, // 32 QAM - { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, // 64 QAM - { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, // 128 QAM - { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, // 256 QAM + static const struct qam_params qam_params[] = { + /* Modulation QAM LOCKTHR MSETH AREF AGCREFNYQ ERAGCNYQ_THD */ + [QPSK] = { (5<<2), 0x78, 0x8c, 0x96, 0x78, 0x4c }, + [QAM_16] = { (0<<2), 0x87, 0xa2, 0x91, 0x8c, 0x57 }, + [QAM_32] = { (1<<2), 0x64, 0x74, 0x96, 0x8c, 0x57 }, + [QAM_64] = { (2<<2), 0x46, 0x43, 0x6a, 0x6a, 0x44 }, + [QAM_128] = { (3<<2), 0x36, 0x34, 0x7e, 0x78, 0x4c }, + [QAM_256] = { (4<<2), 0x26, 0x23, 0x6c, 0x5c, 0x3c }, }; - int qam = p->u.qam.modulation; + switch (delsys) { + case SYS_DVBC_ANNEX_A: + is_annex_c = false; + break; + case SYS_DVBC_ANNEX_C: + is_annex_c = true; + break; + default: + return -EINVAL; + } - if (qam < 0 || qam > 5) + /* + * gcc optimizes the code bellow the same way as it would code: + * "if (qam > 5) return -EINVAL;" + * Yet, the code is clearer, as it shows what QAM standards are + * supported by the driver, and avoids the usage of magic numbers on + * it. + */ + switch (qam) { + case QPSK: + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + break; + default: return -EINVAL; + } if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - tda10023_set_symbolrate (state, p->u.qam.symbol_rate); - tda10023_writereg (state, 0x05, qamvals[qam][1]); - tda10023_writereg (state, 0x08, qamvals[qam][2]); - tda10023_writereg (state, 0x09, qamvals[qam][3]); - tda10023_writereg (state, 0xb4, qamvals[qam][4]); - tda10023_writereg (state, 0xb6, qamvals[qam][5]); - -// tda10023_writereg (state, 0x04, (p->inversion?0x12:0x32)); -// tda10023_writebit (state, 0x04, 0x60, (p->inversion?0:0x20)); - tda10023_writebit (state, 0x04, 0x40, 0x40); - tda10023_setup_reg0 (state, qamvals[qam][0]); + tda10023_set_symbolrate(state, c->symbol_rate); + tda10023_writereg(state, 0x05, qam_params[qam].lockthr); + tda10023_writereg(state, 0x08, qam_params[qam].mseth); + tda10023_writereg(state, 0x09, qam_params[qam].aref); + tda10023_writereg(state, 0xb4, qam_params[qam].agcrefnyq); + tda10023_writereg(state, 0xb6, qam_params[qam].eragnyq_thd); +#if 0 + tda10023_writereg(state, 0x04, (c->inversion ? 0x12 : 0x32)); + tda10023_writebit(state, 0x04, 0x60, (c->inversion ? 0 : 0x20)); +#endif + tda10023_writebit(state, 0x04, 0x40, 0x40); + + if (is_annex_c) + tda10023_writebit(state, 0x3d, 0xfc, 0x03); + else + tda10023_writebit(state, 0x3d, 0xfc, 0x02); + + tda10023_setup_reg0(state, qam_params[qam].qam); return 0; } @@ -418,8 +456,9 @@ static int tda10023_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda10023_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10023_state* state = fe->demodulator_priv; int sync,inv; s8 afc = 0; @@ -433,17 +472,17 @@ static int tda10023_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa printk(sync & 2 ? "DVB: TDA10023(%d): AFC (%d) %dHz\n" : "DVB: TDA10023(%d): [AFC (%d) %dHz]\n", state->frontend.dvb->num, afc, - -((s32)p->u.qam.symbol_rate * afc) >> 10); + -((s32)p->symbol_rate * afc) >> 10); } p->inversion = (inv&0x20?0:1); - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; - p->u.qam.fec_inner = FEC_NONE; + p->fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) - p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + p->frequency -= ((s32)p->symbol_rate * afc) >> 10; return 0; } @@ -534,10 +573,9 @@ error: } static struct dvb_frontend_ops tda10023_ops = { - + .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, .info = { .name = "Philips TDA10023 DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, @@ -557,7 +595,6 @@ static struct dvb_frontend_ops tda10023_ops = { .set_frontend = tda10023_set_parameters, .get_frontend = tda10023_get_frontend, - .read_status = tda10023_read_status, .read_ber = tda10023_read_ber, .read_signal_strength = tda10023_read_signal_strength, diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index 7f105946a434..71fb63299de7 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c @@ -153,7 +153,7 @@ struct tda10048_state { u32 pll_pfactor; u32 sample_freq; - enum fe_bandwidth bandwidth; + u32 bandwidth; }; static struct init_tab { @@ -341,21 +341,14 @@ static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz, { struct tda10048_state *state = fe->demodulator_priv; u64 t, z; - u32 b = 8000000; dprintk(1, "%s()\n", __func__); if (sample_freq_hz == 0) return -EINVAL; - if (bw == BANDWIDTH_6_MHZ) - b = 6000000; - else - if (bw == BANDWIDTH_7_MHZ) - b = 7000000; - /* WREF = (B / (7 * fs)) * 2^31 */ - t = b * 10; + t = bw * 10; /* avoid warning: this decimal constant is unsigned only in ISO C90 */ /* t *= 2147483648 on 32bit platforms */ t *= (2048 * 1024); @@ -378,25 +371,18 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, { struct tda10048_state *state = fe->demodulator_priv; u64 t; - u32 b = 8000000; dprintk(1, "%s()\n", __func__); if (sample_freq_hz == 0) return -EINVAL; - if (bw == BANDWIDTH_6_MHZ) - b = 6000000; - else - if (bw == BANDWIDTH_7_MHZ) - b = 7000000; - /* INVWREF = ((7 * fs) / B) * 2^5 */ t = sample_freq_hz; t *= 7; t *= 32; t *= 10; - do_div(t, b); + do_div(t, bw); t += 5; do_div(t, 10); @@ -407,16 +393,16 @@ static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz, } static int tda10048_set_bandwidth(struct dvb_frontend *fe, - enum fe_bandwidth bw) + u32 bw) { struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(bw=%d)\n", __func__, bw); /* Bandwidth setting may need to be adjusted */ switch (bw) { - case BANDWIDTH_6_MHZ: - case BANDWIDTH_7_MHZ: - case BANDWIDTH_8_MHZ: + case 6000000: + case 7000000: + case 8000000: tda10048_set_wref(fe, state->sample_freq, bw); tda10048_set_invwref(fe, state->sample_freq, bw); break; @@ -430,7 +416,7 @@ static int tda10048_set_bandwidth(struct dvb_frontend *fe, return 0; } -static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) +static int tda10048_set_if(struct dvb_frontend *fe, u32 bw) { struct tda10048_state *state = fe->demodulator_priv; struct tda10048_config *config = &state->config; @@ -441,13 +427,13 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw) /* based on target bandwidth and clk we calculate pll factors */ switch (bw) { - case BANDWIDTH_6_MHZ: + case 6000000: if_freq_khz = config->dtv6_if_freq_khz; break; - case BANDWIDTH_7_MHZ: + case 7000000: if_freq_khz = config->dtv7_if_freq_khz; break; - case BANDWIDTH_8_MHZ: + case 8000000: if_freq_khz = config->dtv8_if_freq_khz; break; default: @@ -601,7 +587,7 @@ static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion) /* Retrieve the demod settings */ static int tda10048_get_tps(struct tda10048_state *state, - struct dvb_ofdm_parameters *p) + struct dtv_frontend_properties *p) { u8 val; @@ -612,27 +598,27 @@ static int tda10048_get_tps(struct tda10048_state *state, val = tda10048_readreg(state, TDA10048_OUT_CONF2); switch ((val & 0x60) >> 5) { case 0: - p->constellation = QPSK; + p->modulation = QPSK; break; case 1: - p->constellation = QAM_16; + p->modulation = QAM_16; break; case 2: - p->constellation = QAM_64; + p->modulation = QAM_64; break; } switch ((val & 0x18) >> 3) { case 0: - p->hierarchy_information = HIERARCHY_NONE; + p->hierarchy = HIERARCHY_NONE; break; case 1: - p->hierarchy_information = HIERARCHY_1; + p->hierarchy = HIERARCHY_1; break; case 2: - p->hierarchy_information = HIERARCHY_2; + p->hierarchy = HIERARCHY_2; break; case 3: - p->hierarchy_information = HIERARCHY_4; + p->hierarchy = HIERARCHY_4; break; } switch (val & 0x07) { @@ -738,17 +724,17 @@ static int tda10048_output_mode(struct dvb_frontend *fe, int serial) /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ /* TODO: Support manual tuning with specific params */ -static int tda10048_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda10048_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency); /* Update the I/F pll's if the bandwidth changes */ - if (p->u.ofdm.bandwidth != state->bandwidth) { - tda10048_set_if(fe, p->u.ofdm.bandwidth); - tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth); + if (p->bandwidth_hz != state->bandwidth) { + tda10048_set_if(fe, p->bandwidth_hz); + tda10048_set_bandwidth(fe, p->bandwidth_hz); } if (fe->ops.tuner_ops.set_params) { @@ -756,7 +742,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -797,8 +783,8 @@ static int tda10048_init(struct dvb_frontend *fe) tda10048_set_inversion(fe, config->inversion); /* Establish default RF values */ - tda10048_set_if(fe, BANDWIDTH_8_MHZ); - tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ); + tda10048_set_if(fe, 8000000); + tda10048_set_bandwidth(fe, 8000000); /* Ensure we leave the gate closed */ tda10048_i2c_gate_ctrl(fe, 0); @@ -1042,9 +1028,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int tda10048_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda10048_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda10048_state *state = fe->demodulator_priv; dprintk(1, "%s()\n", __func__); @@ -1052,7 +1038,7 @@ static int tda10048_get_frontend(struct dvb_frontend *fe, p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1) & 0x20 ? INVERSION_ON : INVERSION_OFF; - return tda10048_get_tps(state, &p->u.ofdm); + return tda10048_get_tps(state, p); } static int tda10048_get_tune_settings(struct dvb_frontend *fe, @@ -1126,7 +1112,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, memcpy(&state->config, config, sizeof(*config)); state->i2c = i2c; state->fwloaded = config->no_firmware; - state->bandwidth = BANDWIDTH_8_MHZ; + state->bandwidth = 8000000; /* check if the demod is present */ if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048) @@ -1152,11 +1138,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, tda10048_establish_defaults(&state->frontend); /* Set the xtal and freq defaults */ - if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0) + if (tda10048_set_if(&state->frontend, 8000000) != 0) goto error; /* Default bandwidth */ - if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0) + if (tda10048_set_bandwidth(&state->frontend, 8000000) != 0) goto error; /* Leave the gate closed */ @@ -1171,10 +1157,9 @@ error: EXPORT_SYMBOL(tda10048_attach); static struct dvb_frontend_ops tda10048_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "NXP TDA10048HN DVB-T", - .type = FE_OFDM, .frequency_min = 177000000, .frequency_max = 858000000, .frequency_stepsize = 166666, diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index ea485d923550..ae6f22aae677 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -224,22 +224,22 @@ static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state) } static int tda10045h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) + u32 bandwidth) { static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; static u8 bandwidth_7mhz[] = { 0x02, 0x00, 0x37, 0x00, 0x4a, 0x2f, 0x6d, 0x76, 0xdb }; static u8 bandwidth_8mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x48, 0x17, 0x89, 0xc7, 0x14 }; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); break; - case BANDWIDTH_7_MHZ: + case 7000000: tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); break; - case BANDWIDTH_8_MHZ: + case 8000000: tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); break; @@ -253,7 +253,7 @@ static int tda10045h_set_bandwidth(struct tda1004x_state *state, } static int tda10046h_set_bandwidth(struct tda1004x_state *state, - fe_bandwidth_t bandwidth) + u32 bandwidth) { static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; @@ -270,7 +270,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, else tda10046_clk53m = 1; switch (bandwidth) { - case BANDWIDTH_6_MHZ: + case 6000000: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz_53M, sizeof(bandwidth_6mhz_53M)); @@ -283,7 +283,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, } break; - case BANDWIDTH_7_MHZ: + case 7000000: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz_53M, sizeof(bandwidth_7mhz_53M)); @@ -296,7 +296,7 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state, } break; - case BANDWIDTH_8_MHZ: + case 8000000: if (tda10046_clk53m) tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz_53M, sizeof(bandwidth_8mhz_53M)); @@ -409,7 +409,7 @@ static int tda10045_fwupload(struct dvb_frontend* fe) msleep(10); /* set parameters */ - tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); + tda10045h_set_bandwidth(state, 8000000); ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); release_firmware(fw); @@ -473,7 +473,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe) tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x3f); break; } - tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + tda10046h_set_bandwidth(state, 8000000); /* default bandwidth 8 MHz */ /* let the PLLs settle */ msleep(120); } @@ -697,9 +697,9 @@ static int tda10046_init(struct dvb_frontend* fe) return 0; } -static int tda1004x_set_fe(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fe_params) +static int tda1004x_set_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda1004x_state* state = fe->demodulator_priv; int tmp; int inversion; @@ -718,7 +718,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set frequency if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } @@ -726,37 +726,37 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. if (state->demod_type == TDA1004X_DEMOD_TDA10045) { - fe_params->u.ofdm.code_rate_HP = FEC_AUTO; - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; + fe_params->code_rate_HP = FEC_AUTO; + fe_params->guard_interval = GUARD_INTERVAL_AUTO; + fe_params->transmission_mode = TRANSMISSION_MODE_AUTO; } // Set standard params.. or put them to auto - if ((fe_params->u.ofdm.code_rate_HP == FEC_AUTO) || - (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || - (fe_params->u.ofdm.constellation == QAM_AUTO) || - (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { + if ((fe_params->code_rate_HP == FEC_AUTO) || + (fe_params->code_rate_LP == FEC_AUTO) || + (fe_params->modulation == QAM_AUTO) || + (fe_params->hierarchy == HIERARCHY_AUTO)) { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto - tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); /* turn off modulation bits */ tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits } else { tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto // set HP FEC - tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); + tmp = tda1004x_encode_fec(fe_params->code_rate_HP); if (tmp < 0) return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); // set LP FEC - tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); + tmp = tda1004x_encode_fec(fe_params->code_rate_LP); if (tmp < 0) return tmp; tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); - // set constellation - switch (fe_params->u.ofdm.constellation) { + /* set modulation */ + switch (fe_params->modulation) { case QPSK: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); break; @@ -774,7 +774,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set hierarchy - switch (fe_params->u.ofdm.hierarchy_information) { + switch (fe_params->hierarchy) { case HIERARCHY_NONE: tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); break; @@ -799,11 +799,11 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set bandwidth switch (state->demod_type) { case TDA1004X_DEMOD_TDA10045: - tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + tda10045h_set_bandwidth(state, fe_params->bandwidth_hz); break; case TDA1004X_DEMOD_TDA10046: - tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); + tda10046h_set_bandwidth(state, fe_params->bandwidth_hz); break; } @@ -825,7 +825,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set guard interval - switch (fe_params->u.ofdm.guard_interval) { + switch (fe_params->guard_interval) { case GUARD_INTERVAL_1_32: tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); @@ -856,7 +856,7 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set transmission mode - switch (fe_params->u.ofdm.transmission_mode) { + switch (fe_params->transmission_mode) { case TRANSMISSION_MODE_2K: tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); @@ -895,8 +895,9 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, return 0; } -static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) +static int tda1004x_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __func__); @@ -913,13 +914,13 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete case TDA1004X_DEMOD_TDA10045: switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { case 0x14: - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fe_params->bandwidth_hz = 8000000; break; case 0xdb: - fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + fe_params->bandwidth_hz = 7000000; break; case 0x4f: - fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + fe_params->bandwidth_hz = 6000000; break; } break; @@ -927,73 +928,73 @@ static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_paramete switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { case 0x5c: case 0x54: - fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; + fe_params->bandwidth_hz = 8000000; break; case 0x6a: case 0x60: - fe_params->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; + fe_params->bandwidth_hz = 7000000; break; case 0x7b: case 0x70: - fe_params->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; + fe_params->bandwidth_hz = 6000000; break; } break; } // FEC - fe_params->u.ofdm.code_rate_HP = + fe_params->code_rate_HP = tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); - fe_params->u.ofdm.code_rate_LP = + fe_params->code_rate_LP = tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); - // constellation + /* modulation */ switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { case 0: - fe_params->u.ofdm.constellation = QPSK; + fe_params->modulation = QPSK; break; case 1: - fe_params->u.ofdm.constellation = QAM_16; + fe_params->modulation = QAM_16; break; case 2: - fe_params->u.ofdm.constellation = QAM_64; + fe_params->modulation = QAM_64; break; } // transmission mode - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + fe_params->transmission_mode = TRANSMISSION_MODE_2K; if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) - fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + fe_params->transmission_mode = TRANSMISSION_MODE_8K; // guard interval switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { case 0: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + fe_params->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + fe_params->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + fe_params->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + fe_params->guard_interval = GUARD_INTERVAL_1_4; break; } // hierarchy switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { case 0: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; + fe_params->hierarchy = HIERARCHY_NONE; break; case 1: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_1; + fe_params->hierarchy = HIERARCHY_1; break; case 2: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_2; + fe_params->hierarchy = HIERARCHY_2; break; case 3: - fe_params->u.ofdm.hierarchy_information = HIERARCHY_4; + fe_params->hierarchy = HIERARCHY_4; break; } @@ -1231,9 +1232,9 @@ static void tda1004x_release(struct dvb_frontend* fe) } static struct dvb_frontend_ops tda10045_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Philips TDA10045H DVB-T", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, @@ -1301,9 +1302,9 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, } static struct dvb_frontend_ops tda10046_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Philips TDA10046H DVB-T", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/frontends/tda10071.c b/drivers/media/dvb/frontends/tda10071.c index 0c37434d19e2..a99205026751 100644 --- a/drivers/media/dvb/frontends/tda10071.c +++ b/drivers/media/dvb/frontends/tda10071.c @@ -636,8 +636,7 @@ error: return ret; } -static int tda10071_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tda10071_set_frontend(struct dvb_frontend *fe) { struct tda10071_priv *priv = fe->demodulator_priv; struct tda10071_cmd cmd; @@ -777,8 +776,7 @@ error: return ret; } -static int tda10071_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int tda10071_get_frontend(struct dvb_frontend *fe) { struct tda10071_priv *priv = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1217,9 +1215,9 @@ error: EXPORT_SYMBOL(tda10071_attach); static struct dvb_frontend_ops tda10071_ops = { + .delsys = { SYS_DVBT, SYS_DVBT2 }, .info = { .name = "NXP TDA10071", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_tolerance = 5000, diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index f2c8faac6f36..fcfe2e080cb0 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -267,7 +267,7 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic } static int tda10086_set_inversion(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) + struct dtv_frontend_properties *fe_params) { u8 invval = 0x80; @@ -292,7 +292,7 @@ static int tda10086_set_inversion(struct tda10086_state *state, } static int tda10086_set_symbol_rate(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) + struct dtv_frontend_properties *fe_params) { u8 dfn = 0; u8 afs = 0; @@ -303,7 +303,7 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state, u32 tmp; u32 bdr; u32 bdri; - u32 symbol_rate = fe_params->u.qpsk.symbol_rate; + u32 symbol_rate = fe_params->symbol_rate; dprintk ("%s %i\n", __func__, symbol_rate); @@ -367,13 +367,13 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state, } static int tda10086_set_fec(struct tda10086_state *state, - struct dvb_frontend_parameters *fe_params) + struct dtv_frontend_properties *fe_params) { u8 fecval; - dprintk ("%s %i\n", __func__, fe_params->u.qpsk.fec_inner); + dprintk("%s %i\n", __func__, fe_params->fec_inner); - switch(fe_params->u.qpsk.fec_inner) { + switch (fe_params->fec_inner) { case FEC_1_2: fecval = 0x00; break; @@ -409,9 +409,9 @@ static int tda10086_set_fec(struct tda10086_state *state, return 0; } -static int tda10086_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fe_params) +static int tda10086_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda10086_state *state = fe->demodulator_priv; int ret; u32 freq = 0; @@ -425,7 +425,7 @@ static int tda10086_set_frontend(struct dvb_frontend* fe, /* set params */ if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, fe_params); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); @@ -452,13 +452,14 @@ static int tda10086_set_frontend(struct dvb_frontend* fe, tda10086_write_mask(state, 0x10, 0x40, 0x40); tda10086_write_mask(state, 0x00, 0x01, 0x00); - state->symbol_rate = fe_params->u.qpsk.symbol_rate; + state->symbol_rate = fe_params->symbol_rate; state->frequency = fe_params->frequency; return 0; } -static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) +static int tda10086_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda10086_state* state = fe->demodulator_priv; u8 val; int tmp; @@ -467,7 +468,7 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa dprintk ("%s\n", __func__); /* check for invalid symbol rate */ - if (fe_params->u.qpsk.symbol_rate < 500000) + if (fe_params->symbol_rate < 500000) return -EINVAL; /* calculate the updated frequency (note: we convert from Hz->kHz) */ @@ -516,34 +517,34 @@ static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa tmp |= 0xffffff00; tmp = (tmp * 480 * (1<<1)) / 128; tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000); - fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp; + fe_params->symbol_rate = state->symbol_rate + tmp; /* the FEC */ val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4; switch(val) { case 0x00: - fe_params->u.qpsk.fec_inner = FEC_1_2; + fe_params->fec_inner = FEC_1_2; break; case 0x01: - fe_params->u.qpsk.fec_inner = FEC_2_3; + fe_params->fec_inner = FEC_2_3; break; case 0x02: - fe_params->u.qpsk.fec_inner = FEC_3_4; + fe_params->fec_inner = FEC_3_4; break; case 0x03: - fe_params->u.qpsk.fec_inner = FEC_4_5; + fe_params->fec_inner = FEC_4_5; break; case 0x04: - fe_params->u.qpsk.fec_inner = FEC_5_6; + fe_params->fec_inner = FEC_5_6; break; case 0x05: - fe_params->u.qpsk.fec_inner = FEC_6_7; + fe_params->fec_inner = FEC_6_7; break; case 0x06: - fe_params->u.qpsk.fec_inner = FEC_7_8; + fe_params->fec_inner = FEC_7_8; break; case 0x07: - fe_params->u.qpsk.fec_inner = FEC_8_9; + fe_params->fec_inner = FEC_8_9; break; } @@ -664,29 +665,31 @@ static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + if (p->symbol_rate > 20000000) { fesettings->min_delay_ms = 50; fesettings->step_size = 2000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { + } else if (p->symbol_rate > 12000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1500; fesettings->max_drift = 9000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { + } else if (p->symbol_rate > 8000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 1000; fesettings->max_drift = 8000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { + } else if (p->symbol_rate > 4000000) { fesettings->min_delay_ms = 100; fesettings->step_size = 500; fesettings->max_drift = 7000; - } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { + } else if (p->symbol_rate > 2000000) { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = p->symbol_rate / 8000; fesettings->max_drift = 14 * fesettings->step_size; } else { fesettings->min_delay_ms = 200; - fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); + fesettings->step_size = p->symbol_rate / 8000; fesettings->max_drift = 18 * fesettings->step_size; } @@ -701,10 +704,9 @@ static void tda10086_release(struct dvb_frontend* fe) } static struct dvb_frontend_ops tda10086_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Philips TDA10086 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/tda18271c2dd.c b/drivers/media/dvb/frontends/tda18271c2dd.c index 1b1bf200c55c..86da3d816498 100644 --- a/drivers/media/dvb/frontends/tda18271c2dd.c +++ b/drivers/media/dvb/frontends/tda18271c2dd.c @@ -1123,55 +1123,51 @@ static int release(struct dvb_frontend *fe) return 0; } -/* - * As defined on EN 300 429 Annex A and on ITU-T J.83 annex A, the DVB-C - * roll-off factor is 0.15. - * According with the specs, the amount of the needed bandwith is given by: - * Bw = Symbol_rate * (1 + 0.15) - * As such, the maximum symbol rate supported by 6 MHz is - * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds - *NOTE: For ITU-T J.83 Annex C, the roll-off factor is 0.13. So: - * max_symbol_rate = 6 MHz / 1.13 = 5309735 Baud - * That means that an adjustment is needed for Japan, - * but, as currently DRX-K is hardcoded to Annex A, let's stick - * with 0.15 roll-off factor. - */ -#define MAX_SYMBOL_RATE_6MHz 5217391 -static int set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int set_params(struct dvb_frontend *fe) { struct tda_state *state = fe->tuner_priv; int status = 0; int Standard; + u32 bw = fe->dtv_property_cache.bandwidth_hz; + u32 delsys = fe->dtv_property_cache.delivery_system; - state->m_Frequency = params->frequency; + state->m_Frequency = fe->dtv_property_cache.frequency; - if (fe->ops.info.type == FE_OFDM) - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (delsys) { + case SYS_DVBT: + case SYS_DVBT2: + switch (bw) { + case 6000000: Standard = HF_DVBT_6MHZ; break; - case BANDWIDTH_7_MHZ: + case 7000000: Standard = HF_DVBT_7MHZ; break; - default: - case BANDWIDTH_8_MHZ: + case 8000000: Standard = HF_DVBT_8MHZ; break; + default: + return -EINVAL; } - else if (fe->ops.info.type == FE_QAM) { - if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + if (bw <= 6000000) Standard = HF_DVBC_6MHZ; + else if (bw <= 7000000) + Standard = HF_DVBC_7MHZ; else Standard = HF_DVBC_8MHZ; - } else + break; + default: return -EINVAL; + } do { - status = RFTrackingFiltersCorrection(state, params->frequency); + status = RFTrackingFiltersCorrection(state, state->m_Frequency); if (status < 0) break; - status = ChannelConfiguration(state, params->frequency, Standard); + status = ChannelConfiguration(state, state->m_Frequency, + Standard); if (status < 0) break; diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 9369f7442f27..15912c96926a 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -315,18 +315,19 @@ static int tda8083_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda8083_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda8083_state* state = fe->demodulator_priv; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } tda8083_set_inversion (state, p->inversion); - tda8083_set_fec (state, p->u.qpsk.fec_inner); - tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); + tda8083_set_fec(state, p->fec_inner); + tda8083_set_symbolrate(state, p->symbol_rate); tda8083_writereg (state, 0x00, 0x3c); tda8083_writereg (state, 0x00, 0x04); @@ -334,16 +335,17 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return 0; } -static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int tda8083_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda8083_state* state = fe->demodulator_priv; /* FIXME: get symbolrate & frequency offset...*/ /*p->frequency = ???;*/ p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = tda8083_get_fec (state); - /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/ + p->fec_inner = tda8083_get_fec(state); + /*p->symbol_rate = tda8083_get_symbolrate (state);*/ return 0; } @@ -438,10 +440,9 @@ error: } static struct dvb_frontend_ops tda8083_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "Philips TDA8083 DVB-S", - .type = FE_QPSK, .frequency_min = 920000, /* TDA8060 */ .frequency_max = 2200000, /* TDA8060 */ .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c index 06c94800b940..04bbcc24de0a 100644 --- a/drivers/media/dvb/frontends/tda826x.c +++ b/drivers/media/dvb/frontends/tda826x.c @@ -71,8 +71,9 @@ static int tda826x_sleep(struct dvb_frontend *fe) return (ret == 1) ? 0 : ret; } -static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda826x_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct tda826x_priv *priv = fe->tuner_priv; int ret; u32 div; @@ -83,11 +84,11 @@ static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_param dprintk("%s:\n", __func__); - div = (params->frequency + (1000-1)) / 1000; + div = (p->frequency + (1000-1)) / 1000; /* BW = ((1 + RO) * SR/2 + 5) * 1.3 [SR in MSPS, BW in MHz] */ /* with R0 = 0.35 and some transformations: */ - ksyms = params->u.qpsk.symbol_rate / 1000; + ksyms = p->symbol_rate / 1000; bandwidth = (878 * ksyms + 6500000) / 1000000 + 1; if (bandwidth < 5) bandwidth = 5; diff --git a/drivers/media/dvb/frontends/tdhd1.h b/drivers/media/dvb/frontends/tdhd1.h index 51f170678650..17750985db0c 100644 --- a/drivers/media/dvb/frontends/tdhd1.h +++ b/drivers/media/dvb/frontends/tdhd1.h @@ -40,24 +40,25 @@ static struct tda1004x_config alps_tdhd1_204a_config = { .request_firmware = alps_tdhd1_204_request_firmware }; -static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct i2c_adapter *i2c = fe->tuner_priv; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; u32 div; - div = (params->frequency + 36166666) / 166666; + div = (p->frequency + 36166666) / 166666; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85; - if (params->frequency >= 174000000 && params->frequency <= 230000000) + if (p->frequency >= 174000000 && p->frequency <= 230000000) data[3] = 0x02; - else if (params->frequency >= 470000000 && params->frequency <= 823000000) + else if (p->frequency >= 470000000 && p->frequency <= 823000000) data[3] = 0x0C; - else if (params->frequency > 823000000 && params->frequency <= 862000000) + else if (p->frequency > 823000000 && p->frequency <= 862000000) data[3] = 0x8C; else return -EINVAL; diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c index bcb95c2ef296..029384d1fddd 100644 --- a/drivers/media/dvb/frontends/tua6100.c +++ b/drivers/media/dvb/frontends/tua6100.c @@ -67,9 +67,9 @@ static int tua6100_sleep(struct dvb_frontend *fe) return (ret == 1) ? 0 : ret; } -static int tua6100_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int tua6100_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tua6100_priv *priv = fe->tuner_priv; u32 div; u32 prediv; @@ -85,36 +85,37 @@ static int tua6100_set_params(struct dvb_frontend *fe, #define _ri 4000000 // setup register 0 - if (params->frequency < 2000000) { + if (c->frequency < 2000000) reg0[1] = 0x03; - } else { + else reg0[1] = 0x07; - } // setup register 1 - if (params->frequency < 1630000) { + if (c->frequency < 1630000) reg1[1] = 0x2c; - } else { + else reg1[1] = 0x0c; - } + if (_P == 64) reg1[1] |= 0x40; - if (params->frequency >= 1525000) + if (c->frequency >= 1525000) reg1[1] |= 0x80; // register 2 reg2[1] = (_R >> 8) & 0x03; reg2[2] = _R; - if (params->frequency < 1455000) { + if (c->frequency < 1455000) reg2[1] |= 0x1c; - } else if (params->frequency < 1630000) { + else if (c->frequency < 1630000) reg2[1] |= 0x0c; - } else { + else reg2[1] |= 0x1c; - } - // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz) - prediv = (params->frequency * _R) / (_ri / 1000); + /* + * The N divisor ratio (note: c->frequency is in kHz, but we + * need it in Hz) + */ + prediv = (c->frequency * _R) / (_ri / 1000); div = prediv / _P; reg1[1] |= (div >> 9) & 0x03; reg1[2] = div >> 1; diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 550a07a8a997..bb42b563c42d 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -205,25 +205,26 @@ static int ves1820_init(struct dvb_frontend* fe) return 0; } -static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1820_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1820_state* state = fe->demodulator_priv; static const u8 reg0x00[] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; static const u8 reg0x01[] = { 140, 140, 106, 100, 92 }; static const u8 reg0x05[] = { 135, 100, 70, 54, 38 }; static const u8 reg0x08[] = { 162, 116, 67, 52, 35 }; static const u8 reg0x09[] = { 145, 150, 106, 126, 107 }; - int real_qam = p->u.qam.modulation - QAM_16; + int real_qam = p->modulation - QAM_16; if (real_qam < 0 || real_qam > 4) return -EINVAL; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - ves1820_set_symbolrate(state, p->u.qam.symbol_rate); + ves1820_set_symbolrate(state, p->symbol_rate); ves1820_writereg(state, 0x34, state->pwm); ves1820_writereg(state, 0x01, reg0x01[real_qam]); @@ -309,8 +310,9 @@ static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1820_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1820_state* state = fe->demodulator_priv; int sync; s8 afc = 0; @@ -320,7 +322,7 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (verbose) { /* AFC only valid when carrier has been recovered */ printk(sync & 2 ? "ves1820: AFC (%d) %dHz\n" : - "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10); + "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->symbol_rate * afc) >> 10); } if (!state->config->invert) { @@ -329,13 +331,13 @@ static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; } - p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + p->modulation = ((state->reg0 >> 2) & 7) + QAM_16; - p->u.qam.fec_inner = FEC_NONE; + p->fec_inner = FEC_NONE; p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) - p->frequency -= ((s32) p->u.qam.symbol_rate * afc) >> 10; + p->frequency -= ((s32) p->symbol_rate * afc) >> 10; return 0; } @@ -405,10 +407,9 @@ error: } static struct dvb_frontend_ops ves1820_ops = { - + .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "VLSI VES1820 DVB-C", - .type = FE_QAM, .frequency_stepsize = 62500, .frequency_min = 47000000, .frequency_max = 862000000, diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c index 8d7854c2fb0c..9c17eacaec24 100644 --- a/drivers/media/dvb/frontends/ves1x93.c +++ b/drivers/media/dvb/frontends/ves1x93.c @@ -46,6 +46,7 @@ struct ves1x93_state { u8 *init_1x93_wtab; u8 tab_size; u8 demod_type; + u32 frequency; }; static int debug; @@ -384,31 +385,34 @@ static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } -static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1x93_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1x93_state* state = fe->demodulator_priv; if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, p); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } ves1x93_set_inversion (state, p->inversion); - ves1x93_set_fec (state, p->u.qpsk.fec_inner); - ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); + ves1x93_set_fec(state, p->fec_inner); + ves1x93_set_symbolrate(state, p->symbol_rate); state->inversion = p->inversion; + state->frequency = p->frequency; return 0; } -static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ves1x93_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ves1x93_state* state = fe->demodulator_priv; int afc; afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; - afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; + afc = (afc * (int)(p->symbol_rate/1000/8))/16; - p->frequency -= afc; + p->frequency = state->frequency - afc; /* * inversion indicator is only valid @@ -417,7 +421,7 @@ static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->inversion == INVERSION_AUTO) p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ? INVERSION_OFF : INVERSION_ON; - p->u.qpsk.fec_inner = ves1x93_get_fec (state); + p->fec_inner = ves1x93_get_fec(state); /* XXX FIXME: timing offset !! */ return 0; @@ -506,10 +510,9 @@ error: } static struct dvb_frontend_ops ves1x93_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "VLSI VES1x93 DVB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, /* kHz for QPSK frontends */ diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c index 81aa984c551f..0903d461b8fa 100644 --- a/drivers/media/dvb/frontends/zl10036.c +++ b/drivers/media/dvb/frontends/zl10036.c @@ -305,12 +305,12 @@ static int zl10036_set_gain_params(struct zl10036_state *state, return zl10036_write(state, buf, sizeof(buf)); } -static int zl10036_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int zl10036_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct zl10036_state *state = fe->tuner_priv; int ret = 0; - u32 frequency = params->frequency; + u32 frequency = p->frequency; u32 fbw; int i; u8 c; @@ -326,7 +326,7 @@ static int zl10036_set_params(struct dvb_frontend *fe, * fBW = (alpha*symbolrate)/(2*0.8) * 1.35 / (2*0.8) = 27 / 32 */ - fbw = (27 * params->u.qpsk.symbol_rate) / 32; + fbw = (27 * p->symbol_rate) / 32; /* scale to kHz */ fbw /= 1000; @@ -353,7 +353,7 @@ static int zl10036_set_params(struct dvb_frontend *fe, if (ret < 0) goto error; - ret = zl10036_set_frequency(state, params->frequency); + ret = zl10036_set_frequency(state, p->frequency); if (ret < 0) goto error; diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c index c085e58a94bf..eff9c5fde50a 100644 --- a/drivers/media/dvb/frontends/zl10039.c +++ b/drivers/media/dvb/frontends/zl10039.c @@ -176,9 +176,9 @@ static int zl10039_sleep(struct dvb_frontend *fe) return 0; } -static int zl10039_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int zl10039_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct zl10039_state *state = fe->tuner_priv; u8 buf[6]; u8 bf; @@ -188,12 +188,12 @@ static int zl10039_set_params(struct dvb_frontend *fe, dprintk("%s\n", __func__); dprintk("Set frequency = %d, symbol rate = %d\n", - params->frequency, params->u.qpsk.symbol_rate); + c->frequency, c->symbol_rate); /* Assumed 10.111 MHz crystal oscillator */ /* Cancelled num/den 80 to prevent overflow */ - div = (params->frequency * 1000) / 126387; - fbw = (params->u.qpsk.symbol_rate * 27) / 32000; + div = (c->frequency * 1000) / 126387; + fbw = (c->symbol_rate * 27) / 32000; /* Cancelled num/den 10 to prevent overflow */ bf = ((fbw * 5088) / 1011100) - 1; diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index adbbf6d3d044..ac7237891374 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -37,9 +37,9 @@ struct zl10353_state { struct zl10353_config config; - enum fe_bandwidth bandwidth; - u32 ucblocks; - u32 frequency; + u32 bandwidth; + u32 ucblocks; + u32 frequency; }; static int debug; @@ -122,30 +122,17 @@ static void zl10353_dump_regs(struct dvb_frontend *fe) } static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, - enum fe_bandwidth bandwidth, + u32 bandwidth, u16 *nominal_rate) { struct zl10353_state *state = fe->demodulator_priv; u32 adc_clock = 450560; /* 45.056 MHz */ u64 value; - u8 bw; + u8 bw = bandwidth / 1000000; if (state->config.adc_clock) adc_clock = state->config.adc_clock; - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6; - break; - case BANDWIDTH_7_MHZ: - bw = 7; - break; - case BANDWIDTH_8_MHZ: - default: - bw = 8; - break; - } - value = (u64)10 * (1 << 23) / 7 * 125; value = (bw * value) + adc_clock / 2; do_div(value, adc_clock); @@ -192,16 +179,15 @@ static int zl10353_sleep(struct dvb_frontend *fe) return 0; } -static int zl10353_set_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int zl10353_set_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct zl10353_state *state = fe->demodulator_priv; u16 nominal_rate, input_freq; u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; u16 tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - state->frequency = param->frequency; + state->frequency = c->frequency; zl10353_single_write(fe, RESET, 0x80); udelay(200); @@ -211,42 +197,44 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, zl10353_single_write(fe, AGC_TARGET, 0x28); - if (op->transmission_mode != TRANSMISSION_MODE_AUTO) + if (c->transmission_mode != TRANSMISSION_MODE_AUTO) acq_ctl |= (1 << 0); - if (op->guard_interval != GUARD_INTERVAL_AUTO) + if (c->guard_interval != GUARD_INTERVAL_AUTO) acq_ctl |= (1 << 1); zl10353_single_write(fe, ACQ_CTL, acq_ctl); - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: /* These are extrapolated from the 7 and 8MHz values */ zl10353_single_write(fe, MCLK_RATIO, 0x97); zl10353_single_write(fe, 0x64, 0x34); zl10353_single_write(fe, 0xcc, 0xdd); break; - case BANDWIDTH_7_MHZ: + case 7000000: zl10353_single_write(fe, MCLK_RATIO, 0x86); zl10353_single_write(fe, 0x64, 0x35); zl10353_single_write(fe, 0xcc, 0x73); break; - case BANDWIDTH_8_MHZ: default: + c->bandwidth_hz = 8000000; + /* fall though */ + case 8000000: zl10353_single_write(fe, MCLK_RATIO, 0x75); zl10353_single_write(fe, 0x64, 0x36); zl10353_single_write(fe, 0xcc, 0x73); } - zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); + zl10353_calc_nominal_rate(fe, c->bandwidth_hz, &nominal_rate); zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); - state->bandwidth = op->bandwidth; + state->bandwidth = c->bandwidth_hz; zl10353_calc_input_freq(fe, &input_freq); zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); /* Hint at TPS settings */ - switch (op->code_rate_HP) { + switch (c->code_rate_HP) { case FEC_2_3: tps |= (1 << 7); break; @@ -266,7 +254,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->code_rate_LP) { + switch (c->code_rate_LP) { case FEC_2_3: tps |= (1 << 4); break; @@ -283,14 +271,14 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, case FEC_AUTO: break; case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) + if (c->hierarchy == HIERARCHY_AUTO || + c->hierarchy == HIERARCHY_NONE) break; default: return -EINVAL; } - switch (op->constellation) { + switch (c->modulation) { case QPSK: break; case QAM_AUTO: @@ -304,7 +292,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: case TRANSMISSION_MODE_AUTO: break; @@ -315,7 +303,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->guard_interval) { + switch (c->guard_interval) { case GUARD_INTERVAL_1_32: case GUARD_INTERVAL_AUTO: break; @@ -332,7 +320,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return -EINVAL; } - switch (op->hierarchy_information) { + switch (c->hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: break; @@ -362,12 +350,12 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, */ if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { - fe->ops.tuner_ops.set_params(fe, param); + fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } } else if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); + fe->ops.tuner_ops.calc_regs(fe, pllbuf + 1, 5); pllbuf[1] <<= 1; zl10353_write(fe, pllbuf, sizeof(pllbuf)); } @@ -383,11 +371,10 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, return 0; } -static int zl10353_get_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int zl10353_get_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct zl10353_state *state = fe->demodulator_priv; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; int s6, s9; u16 tps; static const u8 tps_fec_to_api[8] = { @@ -411,66 +398,66 @@ static int zl10353_get_parameters(struct dvb_frontend *fe, tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | zl10353_read_register(state, TPS_RECEIVED_0); - op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; - op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; + c->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; + c->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; switch ((tps >> 13) & 3) { case 0: - op->constellation = QPSK; + c->modulation = QPSK; break; case 1: - op->constellation = QAM_16; + c->modulation = QAM_16; break; case 2: - op->constellation = QAM_64; + c->modulation = QAM_64; break; default: - op->constellation = QAM_AUTO; + c->modulation = QAM_AUTO; break; } - op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : + c->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K; switch ((tps >> 2) & 3) { case 0: - op->guard_interval = GUARD_INTERVAL_1_32; + c->guard_interval = GUARD_INTERVAL_1_32; break; case 1: - op->guard_interval = GUARD_INTERVAL_1_16; + c->guard_interval = GUARD_INTERVAL_1_16; break; case 2: - op->guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - op->guard_interval = GUARD_INTERVAL_1_4; + c->guard_interval = GUARD_INTERVAL_1_4; break; default: - op->guard_interval = GUARD_INTERVAL_AUTO; + c->guard_interval = GUARD_INTERVAL_AUTO; break; } switch ((tps >> 10) & 7) { case 0: - op->hierarchy_information = HIERARCHY_NONE; + c->hierarchy = HIERARCHY_NONE; break; case 1: - op->hierarchy_information = HIERARCHY_1; + c->hierarchy = HIERARCHY_1; break; case 2: - op->hierarchy_information = HIERARCHY_2; + c->hierarchy = HIERARCHY_2; break; case 3: - op->hierarchy_information = HIERARCHY_4; + c->hierarchy = HIERARCHY_4; break; default: - op->hierarchy_information = HIERARCHY_AUTO; + c->hierarchy = HIERARCHY_AUTO; break; } - param->frequency = state->frequency; - op->bandwidth = state->bandwidth; - param->inversion = INVERSION_AUTO; + c->frequency = state->frequency; + c->bandwidth_hz = state->bandwidth; + c->inversion = INVERSION_AUTO; return 0; } @@ -651,10 +638,9 @@ error: } static struct dvb_frontend_ops zl10353_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "Zarlink ZL10353 DVB-T", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c index 2ae0afa7756b..ad013e93ed11 100644 --- a/drivers/media/dvb/mantis/mantis_vp1033.c +++ b/drivers/media/dvb/mantis/mantis_vp1033.c @@ -83,9 +83,9 @@ u8 lgtdqcs001f_inittab[] = { #define MANTIS_MODEL_NAME "VP-1033" #define MANTIS_DEV_TYPE "DVB-S/DSS" -int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; struct i2c_adapter *adapter = &mantis->adapter; @@ -95,14 +95,14 @@ int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; - div = params->frequency / 250; + div = p->frequency / 250; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x83; buf[3] = 0xc0; - if (params->frequency < 1531000) + if (p->frequency < 1531000) buf[3] |= 0x04; else buf[3] &= ~0x04; diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c index 06da0ddf05a7..1ca6837fbe46 100644 --- a/drivers/media/dvb/mantis/mantis_vp2033.c +++ b/drivers/media/dvb/mantis/mantis_vp2033.c @@ -65,8 +65,9 @@ static u8 read_pwm(struct mantis_pci *mantis) return pwm; } -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; struct i2c_adapter *adapter = &mantis->adapter; @@ -77,13 +78,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten #define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); + buf[3] = (p->frequency < 150000000 ? 0x01 : + p->frequency < 445000000 ? 0x02 : 0x04); buf[4] = 0xde; buf[5] = 0x20; diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c index f72b137b7652..d480741afd78 100644 --- a/drivers/media/dvb/mantis/mantis_vp2040.c +++ b/drivers/media/dvb/mantis/mantis_vp2040.c @@ -47,8 +47,9 @@ struct tda10023_config vp2040_tda10023_cu1216_config = { .invert = 1, }; -static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; struct i2c_adapter *adapter = &mantis->adapter; @@ -59,13 +60,13 @@ static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_fronten #define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (p->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); + buf[3] = (p->frequency < 150000000 ? 0x01 : + p->frequency < 445000000 ? 0x02 : 0x04); buf[4] = 0xde; buf[5] = 0x20; diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 056419228363..8418c02bcefe 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -218,7 +218,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, memset(&config, 0, sizeof(config)); config.adr = 0x29 + (chan->number ^ 2); - chan->fe = dvb_attach(drxk_attach, &config, i2c, &chan->fe2); + chan->fe = dvb_attach(drxk_attach, &config, i2c); if (!chan->fe) { printk(KERN_ERR "No DRXK found!\n"); return -ENODEV; diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 80fb51004461..e1f20c236989 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -445,9 +445,9 @@ static inline u32 divide(u32 numerator, u32 denominator) } /* LG Innotek TDTE-E001P (Infineon TUA6034) */ -static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct pluto *pluto = frontend_to_pluto(fe); struct i2c_msg msg; int ret; @@ -478,7 +478,7 @@ static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, else buf[3] = 0x04; - if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) + if (p->bandwidth_hz == 8000000) buf[3] |= 0x08; if (sizeof(buf) == 6) { diff --git a/drivers/media/dvb/pt1/va1j5jf8007s.c b/drivers/media/dvb/pt1/va1j5jf8007s.c index 451641c0c1d2..d980dfb21e5e 100644 --- a/drivers/media/dvb/pt1/va1j5jf8007s.c +++ b/drivers/media/dvb/pt1/va1j5jf8007s.c @@ -385,7 +385,7 @@ va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock) static int va1j5jf8007s_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { @@ -395,7 +395,7 @@ va1j5jf8007s_tune(struct dvb_frontend *fe, state = fe->demodulator_priv; - if (params != NULL) + if (re_tune) state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1; switch (state->tune_state) { @@ -579,9 +579,9 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops va1j5jf8007s_ops = { + .delsys = { SYS_ISDBS }, .info = { .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 1000, diff --git a/drivers/media/dvb/pt1/va1j5jf8007t.c b/drivers/media/dvb/pt1/va1j5jf8007t.c index 0f085c3e571b..2db15159d514 100644 --- a/drivers/media/dvb/pt1/va1j5jf8007t.c +++ b/drivers/media/dvb/pt1/va1j5jf8007t.c @@ -264,7 +264,7 @@ static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state, static int va1j5jf8007t_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, + bool re_tune, unsigned int mode_flags, unsigned int *delay, fe_status_t *status) { @@ -274,7 +274,7 @@ va1j5jf8007t_tune(struct dvb_frontend *fe, state = fe->demodulator_priv; - if (params != NULL) + if (re_tune) state->tune_state = VA1J5JF8007T_SET_FREQUENCY; switch (state->tune_state) { @@ -428,9 +428,9 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe) } static struct dvb_frontend_ops va1j5jf8007t_ops = { + .delsys = { SYS_ISDBT }, .info = { .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", - .type = FE_OFDM, .frequency_min = 90000000, .frequency_max = 770000000, .frequency_stepsize = 142857, diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 37c594f82782..654685c9303e 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -50,7 +50,7 @@ struct smsdvb_client_t { struct completion tune_done; /* todo: save freq/band instead whole struct */ - struct dvb_frontend_parameters fe_params; + struct dtv_frontend_properties fe_params; struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; int event_fe_state; @@ -591,8 +591,7 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe, return 0; } -static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client = @@ -658,8 +657,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, &client->tune_done); } -static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client = @@ -723,8 +721,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe, &client->tune_done); } -static int smsdvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int smsdvb_set_frontend(struct dvb_frontend *fe) { struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); @@ -733,18 +730,18 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe, switch (smscore_get_device_mode(coredev)) { case DEVICE_MODE_DVBT: case DEVICE_MODE_DVBT_BDA: - return smsdvb_dvbt_set_frontend(fe, fep); + return smsdvb_dvbt_set_frontend(fe); case DEVICE_MODE_ISDBT: case DEVICE_MODE_ISDBT_BDA: - return smsdvb_isdbt_set_frontend(fe, fep); + return smsdvb_isdbt_set_frontend(fe); default: return -EINVAL; } } -static int smsdvb_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int smsdvb_get_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); @@ -752,7 +749,7 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe, /* todo: */ memcpy(fep, &client->fe_params, - sizeof(struct dvb_frontend_parameters)); + sizeof(struct dtv_frontend_properties)); return 0; } @@ -789,7 +786,6 @@ static void smsdvb_release(struct dvb_frontend *fe) static struct dvb_frontend_ops smsdvb_fe_ops = { .info = { .name = "Siano Mobile Digital MDTV Receiver", - .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 250000, @@ -873,6 +869,17 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, memcpy(&client->frontend.ops, &smsdvb_fe_ops, sizeof(struct dvb_frontend_ops)); + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + smsdvb_fe_ops.delsys[0] = SYS_DVBT; + break; + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_fe_ops.delsys[0] = SYS_ISDBT; + break; + } + rc = dvb_register_frontend(&client->adapter, &client->frontend); if (rc < 0) { sms_err("frontend registration failed %d", rc); diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 3d20719fce1a..6ecbcf614878 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -991,7 +991,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (feed->type == DMX_TYPE_TS) { if ((feed->ts_type & TS_DECODER) && - (feed->pes_type < DMX_TS_PES_OTHER)) { + (feed->pes_type <= DMX_TS_PES_PCR)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: if (feed->ts_type & TS_DECODER) @@ -1568,20 +1568,27 @@ static int get_firmware(struct av7110* av7110) return ret; } -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u8 pwr = 0; u8 buf[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; + u32 div = (p->frequency + 479500) / 125; - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; - else pwr = 2; + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; + else + pwr = 2; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; @@ -1604,19 +1611,20 @@ static struct ves1x93_config alps_bsrv2_config = { .invert_pwm = 0, }; -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 35937500 + 31250) / 62500; + div = (p->frequency + 35937500 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1635,14 +1643,15 @@ static struct ves1820_config alps_tdbe2_config = { -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 125; + div = p->frequency / 125; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x8e; @@ -1661,11 +1670,12 @@ static struct tda8083_config grundig_29504_451_config = { -static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; - u32 f = params->frequency; + u32 f = p->frequency; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; @@ -1692,16 +1702,17 @@ static struct ves1820_config philips_cd1516_config = { -static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div, pwr; u8 data[4]; struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 36200000) / 166666; + div = (p->frequency + 36200000) / 166666; - if (params->frequency <= 782000000) + if (p->frequency <= 782000000) pwr = 1; else pwr = 2; @@ -1829,8 +1840,9 @@ static u8 nexusca_stv0297_inittab[] = { 0xff, 0xff, }; -static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 data[4]; @@ -1838,19 +1850,19 @@ static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_ struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; int i; - div = (params->frequency + 36150000 + 31250) / 62500; + div = (p->frequency + 36150000 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0xce; - if (params->frequency < 45000000) + if (p->frequency < 45000000) return -EINVAL; - else if (params->frequency < 137000000) + else if (p->frequency < 137000000) data[3] = 0x01; - else if (params->frequency < 403000000) + else if (p->frequency < 403000000) data[3] = 0x02; - else if (params->frequency < 860000000) + else if (p->frequency < 860000000) data[3] = 0x04; else return -EINVAL; @@ -1884,27 +1896,36 @@ static struct stv0297_config nexusca_stv0297_config = { -static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct av7110* av7110 = fe->dvb->priv; u32 div; u8 cfg, cpump, band_select; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (36125000 + params->frequency) / 166666; + div = (36125000 + p->frequency) / 166666; cfg = 0x88; - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 1; - else cpump = 3; + if (p->frequency < 175000000) + cpump = 2; + else if (p->frequency < 390000000) + cpump = 1; + else if (p->frequency < 470000000) + cpump = 2; + else if (p->frequency < 750000000) + cpump = 1; + else + cpump = 3; - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; + if (p->frequency < 175000000) + band_select = 0x0e; + else if (p->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; @@ -1964,15 +1985,14 @@ static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) return ret; } -static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int av7110_fe_set_frontend(struct dvb_frontend *fe) { struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); - if (!ret) { - av7110->saved_fe_params = *params; - ret = av7110->fe_set_frontend(fe, params); - } + if (!ret) + ret = av7110->fe_set_frontend(fe); + return ret; } @@ -2081,7 +2101,7 @@ static void dvb_s_recover(struct av7110* av7110) msleep(20); av7110_fe_set_tone(av7110->fe, av7110->saved_tone); - av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params); + av7110_fe_set_frontend(av7110->fe); } static u8 read_pwm(struct av7110* av7110) diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index d85b8512ac30..88b3b2d6cc0e 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -272,7 +272,6 @@ struct av7110 { /* crash recovery */ void (*recover)(struct av7110* av7110); - struct dvb_frontend_parameters saved_fe_params; fe_sec_voltage_t saved_voltage; fe_sec_tone_mode_t saved_tone; struct dvb_diseqc_master_cmd saved_master_cmd; @@ -286,7 +285,7 @@ struct av7110 { int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); - int (*fe_set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*fe_set_frontend)(struct dvb_frontend *fe); }; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 78d32f7e49fc..8b32e282bf5d 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -502,33 +502,33 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra return 0; } -static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 div; u8 buf[4]; struct budget *budget = (struct budget *) fe->dvb->priv; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((c->frequency < 950000) || (c->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (125 - 1)) / 125; // round correctly + div = (c->frequency + (125 - 1)) / 125; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; buf[3] = 0x20; - if (params->u.qpsk.symbol_rate < 4000000) + if (c->symbol_rate < 4000000) buf[3] |= 1; - if (params->frequency < 1250000) + if (c->frequency < 1250000) buf[3] |= 0; - else if (params->frequency < 1550000) + else if (c->frequency < 1550000) buf[3] |= 0x40; - else if (params->frequency < 2050000) + else if (c->frequency < 2050000) buf[3] |= 0x80; - else if (params->frequency < 2150000) + else if (c->frequency < 2150000) buf[3] |= 0xC0; if (fe->ops.i2c_gate_ctrl) @@ -617,8 +617,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = { .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, }; -static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget *budget = (struct budget *) fe->dvb->priv; u8 buf[6]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -627,13 +628,13 @@ static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f #define CU1216_IF 36125000 #define TUNER_MUL 62500 - u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0xce; - buf[3] = (params->frequency < 150000000 ? 0x01 : - params->frequency < 445000000 ? 0x02 : 0x04); + buf[3] = (c->frequency < 150000000 ? 0x01 : + c->frequency < 445000000 ? 0x02 : 0x04); buf[4] = 0xde; buf[5] = 0x20; @@ -697,8 +698,9 @@ static int philips_tu1216_tuner_init(struct dvb_frontend *fe) return 0; } -static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget *budget = (struct budget *) fe->dvb->priv; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = @@ -707,7 +709,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36166000; + tuner_frequency = c->frequency + 36166000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -732,28 +734,28 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f return -EINVAL; // determine band - if (params->frequency < 49000000) + if (c->frequency < 49000000) return -EINVAL; - else if (params->frequency < 161000000) + else if (c->frequency < 161000000) band = 1; - else if (params->frequency < 444000000) + else if (c->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (c->frequency < 861000000) band = 4; else return -EINVAL; // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: filter = 1; break; @@ -763,7 +765,7 @@ static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_f // calculate divisor // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; // setup tuner buffer tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index ca02e9722172..98e524178765 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -193,7 +193,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) dev->input_phys = budget_ci->ir.phys; dev->input_id.bustype = BUS_PCI; dev->input_id.version = 1; - dev->scanmask = 0xff; if (saa->pci->subsystem_vendor) { dev->input_id.vendor = saa->pci->subsystem_vendor; dev->input_id.product = saa->pci->subsystem_device; @@ -234,6 +233,8 @@ static int msp430_ir_init(struct budget_ci *budget_ci) dev->map_name = RC_MAP_BUDGET_CI_OLD; break; } + if (!budget_ci->ir.full_rc5) + dev->scanmask = 0xff; error = rc_register_device(dev); if (error) { @@ -659,33 +660,33 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, return 0; } -static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (500 - 1)) / 500; // round correctly + div = (p->frequency + (500 - 1)) / 500; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; buf[3] = 0x20; - if (params->u.qpsk.symbol_rate < 4000000) + if (p->symbol_rate < 4000000) buf[3] |= 1; - if (params->frequency < 1250000) + if (p->frequency < 1250000) buf[3] |= 0; - else if (params->frequency < 1550000) + else if (p->frequency < 1550000) buf[3] |= 0x40; - else if (params->frequency < 2050000) + else if (p->frequency < 2050000) buf[3] |= 0x80; - else if (params->frequency < 2150000) + else if (p->frequency < 2150000) buf[3] |= 0xC0; if (fe->ops.i2c_gate_ctrl) @@ -740,8 +741,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) return 0; } -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; @@ -749,7 +751,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36130000; + tuner_frequency = p->frequency + 36130000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -774,30 +776,30 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb return -EINVAL; // determine band - if (params->frequency < 49000000) + if (p->frequency < 49000000) return -EINVAL; - else if (params->frequency < 159000000) + else if (p->frequency < 159000000) band = 1; - else if (params->frequency < 444000000) + else if (p->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (p->frequency < 861000000) band = 4; else return -EINVAL; // setup PLL filter and TDA9889 - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: tda1004x_writereg(fe, 0x0C, 0x14); filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: tda1004x_writereg(fe, 0x0C, 0x80); filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: tda1004x_writereg(fe, 0x0C, 0x14); filter = 1; break; @@ -808,7 +810,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb // calculate divisor // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; @@ -855,8 +857,9 @@ static struct tda1004x_config philips_tdm1316l_config_invert = { .request_firmware = philips_tdm1316l_request_firmware, }; -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[5]; struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, @@ -867,7 +870,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36125000; + tuner_frequency = p->frequency + 36125000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) { @@ -904,7 +907,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc filter = 1; // calculate divisor - tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500; + tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 3395d1a90516..2cb35c23d2ac 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -261,19 +261,25 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c return 0; } -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u8 pwr = 0; u8 buf[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; + u32 div = (p->frequency + 479500) / 125; + + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; else pwr = 2; buf[0] = (div >> 8) & 0x7f; @@ -297,14 +303,15 @@ static struct ves1x93_config alps_bsrv2_config = { .invert_pwm = 0, }; -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 125; + div = p->frequency / 125; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x8e; diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index d238fb9371a7..b21bcce66708 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -200,19 +200,25 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m return 0; } -static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u8 pwr = 0; u8 buf[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (params->frequency + 479500) / 125; - - if (params->frequency > 2000000) pwr = 3; - else if (params->frequency > 1800000) pwr = 2; - else if (params->frequency > 1600000) pwr = 1; - else if (params->frequency > 1200000) pwr = 0; - else if (params->frequency >= 1100000) pwr = 1; + u32 div = (c->frequency + 479500) / 125; + + if (c->frequency > 2000000) + pwr = 3; + else if (c->frequency > 1800000) + pwr = 2; + else if (c->frequency > 1600000) + pwr = 1; + else if (c->frequency > 1200000) + pwr = 0; + else if (c->frequency >= 1100000) + pwr = 1; else pwr = 2; buf[0] = (div >> 8) & 0x7f; @@ -236,19 +242,20 @@ static struct ves1x93_config alps_bsrv2_config = .invert_pwm = 0, }; -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 35937500 + 31250) / 62500; + div = (c->frequency + 35937500 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -263,8 +270,9 @@ static struct ves1820_config alps_tdbe2_config = { .selagc = VES1820_SELAGC_SIGNAMPERR, }; -static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget *budget = fe->dvb->priv; u8 *tuner_addr = fe->tuner_priv; u32 div; @@ -277,19 +285,27 @@ static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dv else msg.addr = 0x61; - div = (36125000 + params->frequency) / 166666; + div = (36125000 + c->frequency) / 166666; cfg = 0x88; - if (params->frequency < 175000000) cpump = 2; - else if (params->frequency < 390000000) cpump = 1; - else if (params->frequency < 470000000) cpump = 2; - else if (params->frequency < 750000000) cpump = 1; - else cpump = 3; + if (c->frequency < 175000000) + cpump = 2; + else if (c->frequency < 390000000) + cpump = 1; + else if (c->frequency < 470000000) + cpump = 2; + else if (c->frequency < 750000000) + cpump = 1; + else + cpump = 3; - if (params->frequency < 175000000) band_select = 0x0e; - else if (params->frequency < 470000000) band_select = 0x05; - else band_select = 0x03; + if (c->frequency < 175000000) + band_select = 0x0e; + else if (c->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; @@ -312,14 +328,15 @@ static struct l64781_config grundig_29504_401_config_activy = { static u8 tuner_address_grundig_29504_401_activy = 0x60; -static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 125; + div = c->frequency / 125; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x8e; @@ -335,14 +352,15 @@ static struct tda8083_config grundig_29504_451_config = { .demod_address = 0x68, }; -static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int s5h1420_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - div = params->frequency / 1000; + div = c->frequency / 1000; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0xc2; diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index e90192fdde11..5b682cc4c814 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1017,19 +1017,20 @@ static u32 functionality(struct i2c_adapter *adapter) -static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdmb7_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 data[4]; struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; u32 div; - div = (params->frequency + 36166667) / 166667; + div = (p->frequency + 36166667) / 166667; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = ((div >> 10) & 0x60) | 0x85; - data[3] = params->frequency < 592000000 ? 0x40 : 0x80; + data[3] = p->frequency < 592000000 ? 0x40 : 0x80; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1071,8 +1072,9 @@ static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) return 0; } -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 tuner_buf[4]; struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; @@ -1080,7 +1082,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency + 36130000; + tuner_frequency = p->frequency + 36130000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) cp = 3; else if (tuner_frequency < 160000000) cp = 5; @@ -1094,25 +1096,29 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb else return -EINVAL; // determine band - if (params->frequency < 49000000) return -EINVAL; - else if (params->frequency < 159000000) band = 1; - else if (params->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) band = 4; + if (p->frequency < 49000000) + return -EINVAL; + else if (p->frequency < 159000000) + band = 1; + else if (p->frequency < 444000000) + band = 2; + else if (p->frequency < 861000000) + band = 4; else return -EINVAL; // setup PLL filter - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (p->bandwidth_hz) { + case 6000000: tda1004x_writereg(fe, 0x0C, 0); filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: tda1004x_writereg(fe, 0x0C, 0); filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: tda1004x_writereg(fe, 0x0C, 0xFF); filter = 1; break; @@ -1123,7 +1129,7 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb // calculate divisor // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; @@ -1273,23 +1279,24 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 return 0; } -static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - if ((params->frequency < 950000) || (params->frequency > 2150000)) + if ((p->frequency < 950000) || (p->frequency > 2150000)) return -EINVAL; - div = (params->frequency + (125 - 1)) / 125; // round correctly + div = (p->frequency + (125 - 1)) / 125; /* round correctly */ buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; buf[3] = 0xC4; - if (params->frequency > 1530000) + if (p->frequency > 1530000) buf[3] = 0xC0; /* BSBE1 wants XCE bit set */ @@ -1316,14 +1323,15 @@ static struct stv0299_config alps_stv0299_config = { .set_symbol_rate = alps_stv0299_set_symbol_rate, }; -static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; u32 div; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - div = params->frequency / 125; + div = p->frequency / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; @@ -1343,19 +1351,20 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = { .demod_address = 0x68, }; -static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb* ttusb = fe->dvb->priv; u32 div; u8 data[4]; struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - div = (params->frequency + 35937500 + 31250) / 62500; + div = (p->frequency + 35937500 + 31250) / 62500; data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1387,8 +1396,9 @@ static u8 read_pwm(struct ttusb* ttusb) } -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; u8 tuner_buf[5]; struct i2c_msg tuner_msg = {.addr = 0x60, @@ -1399,7 +1409,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc u8 band, cp, filter; // determine charge pump - tuner_frequency = params->frequency; + tuner_frequency = p->frequency; if (tuner_frequency < 87000000) {return -EINVAL;} else if (tuner_frequency < 130000000) {cp = 3; band = 1;} else if (tuner_frequency < 160000000) {cp = 5; band = 1;} @@ -1417,7 +1427,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struc // calculate divisor // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz - tuner_frequency = ((params->frequency + 36125000) / 62500); + tuner_frequency = ((p->frequency + 36125000) / 62500); // setup tuner buffer tuner_buf[0] = tuner_frequency >> 8; @@ -1694,10 +1704,8 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb->i2c_adap.dev.parent = &udev->dev; result = i2c_add_adapter(&ttusb->i2c_adap); - if (result) { - dvb_unregister_adapter (&ttusb->adapter); - return result; - } + if (result) + goto err_unregister_adapter; memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); @@ -1714,33 +1722,29 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb->dvb_demux.stop_feed = ttusb_stop_feed; ttusb->dvb_demux.write_to_decoder = NULL; - if ((result = dvb_dmx_init(&ttusb->dvb_demux)) < 0) { + result = dvb_dmx_init(&ttusb->dvb_demux); + if (result < 0) { printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; + result = -ENODEV; + goto err_i2c_del_adapter; } //FIXME dmxdev (nur WAS?) ttusb->dmxdev.filternum = ttusb->dvb_demux.filternum; ttusb->dmxdev.demux = &ttusb->dvb_demux.dmx; ttusb->dmxdev.capabilities = 0; - if ((result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter)) < 0) { + result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter); + if (result < 0) { printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n", result); - dvb_dmx_release(&ttusb->dvb_demux); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; + result = -ENODEV; + goto err_release_dmx; } if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) { printk("ttusb_dvb: dvb_net_init failed!\n"); - dvb_dmxdev_release(&ttusb->dmxdev); - dvb_dmx_release(&ttusb->dvb_demux); - i2c_del_adapter(&ttusb->i2c_adap); - dvb_unregister_adapter (&ttusb->adapter); - return -ENODEV; + result = -ENODEV; + goto err_release_dmxdev; } usb_set_intfdata(intf, (void *) ttusb); @@ -1748,6 +1752,16 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i frontend_init(ttusb); return 0; + +err_release_dmxdev: + dvb_dmxdev_release(&ttusb->dmxdev); +err_release_dmx: + dvb_dmx_release(&ttusb->dvb_demux); +err_i2c_del_adapter: + i2c_del_adapter(&ttusb->i2c_adap); +err_unregister_adapter: + dvb_unregister_adapter (&ttusb->adapter); + return result; } static void ttusb_disconnect(struct usb_interface *intf) diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index 21260aad1e54..5c45c9d0712d 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -87,8 +87,9 @@ static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe, return 0; } -static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, @@ -113,8 +114,9 @@ static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe, return 0; } -static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; u8 b[] = { 0x00, 0x00, 0x00, 0x01, @@ -135,7 +137,7 @@ static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_fron freq = htonl(p->frequency + (state->hi_band ? LOF_HI : LOF_LO)); memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->u.qam.symbol_rate); + sym_rate = htonl(p->symbol_rate); memcpy(&b[12], &sym_rate, sizeof(u32)); band = htonl(state->hi_band ? LOF_HI : LOF_LO); memcpy(&b[24], &band, sizeof(u32)); @@ -241,10 +243,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf } static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { - + .delsys = { SYS_DVBT }, .info = { .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .type = FE_OFDM, .frequency_min = 51000000, .frequency_max = 858000000, .frequency_stepsize = 62500, @@ -265,10 +266,9 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { }; static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { - + .delsys = { SYS_DVBS }, .info = { .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .type = FE_QPSK, .frequency_min = 950000, .frequency_max = 2150000, .frequency_stepsize = 125, diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 6edc9ba81203..6f9eb94e85b3 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -108,8 +108,7 @@ static long media_device_enum_entities(struct media_device *mdev, u_ent.group_id = ent->group_id; u_ent.pads = ent->num_pads; u_ent.links = ent->num_links - ent->num_backlinks; - u_ent.v4l.major = ent->v4l.major; - u_ent.v4l.minor = ent->v4l.minor; + memcpy(&u_ent.raw, &ent->info, sizeof(ent->info)); if (copy_to_user(uent, &u_ent, sizeof(u_ent))) return -EFAULT; return 0; diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index ccd5f0d8a012..e954781c90bf 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -11,6 +11,162 @@ menuconfig RADIO_ADAPTERS if RADIO_ADAPTERS && VIDEO_V4L2 +config RADIO_SI470X + bool "Silicon Labs Si470x FM Radio Receiver support" + depends on VIDEO_V4L2 + +source "drivers/media/radio/si470x/Kconfig" + +config USB_MR800 + tristate "AverMedia MR 800 USB FM radio support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + To compile this driver as a module, choose M here: the + module will be called radio-mr800. + +config USB_DSBR + tristate "D-Link/GemTek USB FM radio support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. Note that the audio is not digital, and + you must connect the line out connector to a sound card or a + set of speakers. + + To compile this driver as a module, choose M here: the + module will be called dsbr100. + +config RADIO_MAXIRADIO + tristate "Guillemot MAXI Radio FM 2000 radio" + depends on VIDEO_V4L2 && PCI + ---help--- + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-maxiradio. + + +config I2C_SI4713 + tristate "I2C driver for Silicon Labs Si4713 device" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want support to Si4713 I2C device. + This device driver supports only i2c bus. + + To compile this driver as a module, choose M here: the + module will be called si4713. + +config RADIO_SI4713 + tristate "Silicon Labs Si4713 FM Radio Transmitter support" + depends on I2C && VIDEO_V4L2 + select I2C_SI4713 + ---help--- + Say Y here if you want support to Si4713 FM Radio Transmitter. + This device can transmit audio through FM. It can transmit + RDS and RBDS signals as well. This module is the v4l2 radio + interface for the i2c driver of this device. + + To compile this driver as a module, choose M here: the + module will be called radio-si4713. + +config RADIO_TEA5764 + tristate "TEA5764 I2C FM radio support" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the TEA5764 FM chip found in + EZX phones. This FM chip is present in EZX phones from Motorola, + connected to internal pxa I2C bus. + + To compile this driver as a module, choose M here: the + module will be called radio-tea5764. + +config RADIO_TEA5764_XTAL + bool "TEA5764 crystal reference" + depends on RADIO_TEA5764=y + default y + help + Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N + here if TEA5764 reference frequency is connected in FREQIN. + +config RADIO_SAA7706H + tristate "SAA7706H Car Radio DSP" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the SAA7706H Car radio Digital + Signal Processor, found for instance on the Russellville development + board. On the russellville the device is connected to internal + timberdale I2C bus. + + To compile this driver as a module, choose M here: the + module will be called SAA7706H. + +config RADIO_TEF6862 + tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" + depends on I2C && VIDEO_V4L2 + ---help--- + Say Y here if you want to use the TEF6862 Car Radio Enhanced + Selectivity Tuner, found for instance on the Russellville development + board. On the russellville the device is connected to internal + timberdale I2C bus. + + To compile this driver as a module, choose M here: the + module will be called TEF6862. + +config RADIO_TIMBERDALE + tristate "Enable the Timberdale radio driver" + depends on MFD_TIMBERDALE && VIDEO_V4L2 + depends on I2C # for RADIO_SAA7706H + select RADIO_TEF6862 + select RADIO_SAA7706H + ---help--- + This is a kind of umbrella driver for the Radio Tuner and DSP + found behind the Timberdale FPGA on the Russellville board. + Enabling this driver will automatically select the DSP and tuner. + +config RADIO_WL1273 + tristate "Texas Instruments WL1273 I2C FM Radio" + depends on I2C && VIDEO_V4L2 + select MFD_CORE + select MFD_WL1273_CORE + select FW_LOADER + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-wl1273. + +# TI's ST based wl128x FM radio +source "drivers/media/radio/wl128x/Kconfig" + +# +# ISA drivers configuration +# + +menuconfig V4L_RADIO_ISA_DRIVERS + bool "ISA radio devices" + depends on ISA + default n + ---help--- + Say Y here to enable support for these ISA drivers. + +if V4L_RADIO_ISA_DRIVERS + config RADIO_CADET tristate "ADS Cadet AM/FM Tuner" depends on ISA && VIDEO_V4L2 @@ -151,21 +307,6 @@ config RADIO_GEMTEK_PROBE following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and 0x28c. -config RADIO_MAXIRADIO - tristate "Guillemot MAXI Radio FM 2000 radio" - depends on VIDEO_V4L2 && PCI - ---help--- - Choose Y here if you have this radio card. This card may also be - found as Gemtek PCI FM. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - <file:Documentation/video4linux/API.html>. - - To compile this driver as a module, choose M here: the - module will be called radio-maxiradio. - config RADIO_MIROPCM20 tristate "miroSOUND PCM20 radio" depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND @@ -316,130 +457,6 @@ config RADIO_ZOLTRIX_PORT help Enter the I/O port of your Zoltrix radio card. -config I2C_SI4713 - tristate "I2C driver for Silicon Labs Si4713 device" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want support to Si4713 I2C device. - This device driver supports only i2c bus. - - To compile this driver as a module, choose M here: the - module will be called si4713. - -config RADIO_SI4713 - tristate "Silicon Labs Si4713 FM Radio Transmitter support" - depends on I2C && VIDEO_V4L2 - select I2C_SI4713 - ---help--- - Say Y here if you want support to Si4713 FM Radio Transmitter. - This device can transmit audio through FM. It can transmit - RDS and RBDS signals as well. This module is the v4l2 radio - interface for the i2c driver of this device. - - To compile this driver as a module, choose M here: the - module will be called radio-si4713. - -config USB_DSBR - tristate "D-Link/GemTek USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called dsbr100. - -config RADIO_SI470X - bool "Silicon Labs Si470x FM Radio Receiver support" - depends on VIDEO_V4L2 - -source "drivers/media/radio/si470x/Kconfig" - -config USB_MR800 - tristate "AverMedia MR 800 USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called radio-mr800. - -config RADIO_TEA5764 - tristate "TEA5764 I2C FM radio support" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEA5764 FM chip found in - EZX phones. This FM chip is present in EZX phones from Motorola, - connected to internal pxa I2C bus. - - To compile this driver as a module, choose M here: the - module will be called radio-tea5764. - -config RADIO_TEA5764_XTAL - bool "TEA5764 crystal reference" - depends on RADIO_TEA5764=y - default y - help - Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N - here if TEA5764 reference frequency is connected in FREQIN. - -config RADIO_SAA7706H - tristate "SAA7706H Car Radio DSP" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the SAA7706H Car radio Digital - Signal Processor, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called SAA7706H. - -config RADIO_TEF6862 - tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEF6862 Car Radio Enhanced - Selectivity Tuner, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called TEF6862. - -config RADIO_TIMBERDALE - tristate "Enable the Timberdale radio driver" - depends on MFD_TIMBERDALE && VIDEO_V4L2 - depends on I2C # for RADIO_SAA7706H - select RADIO_TEF6862 - select RADIO_SAA7706H - ---help--- - This is a kind of umbrella driver for the Radio Tuner and DSP - found behind the Timberdale FPGA on the Russellville board. - Enabling this driver will automatically select the DSP and tuner. - -config RADIO_WL1273 - tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C && VIDEO_V4L2 - select MFD_WL1273_CORE - select FW_LOADER - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - <file:Documentation/video4linux/API.html>. - - To compile this driver as a module, choose M here: the - module will be called radio-wl1273. - -# TI's ST based wl128x FM radio -source "drivers/media/radio/wl128x/Kconfig" +endif # V4L_RADIO_ISA_DRIVERS endif # RADIO_ADAPTERS diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index edadc8449a3d..36ce0611c037 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -47,11 +47,11 @@ MODULE_VERSION("0.0.4"); #endif static int io = CONFIG_RADIO_GEMTEK_PORT; -static int probe = CONFIG_RADIO_GEMTEK_PROBE; -static int hardmute; -static int shutdown = 1; -static int keepmuted = 1; -static int initmute = 1; +static bool probe = CONFIG_RADIO_GEMTEK_PROBE; +static bool hardmute; +static bool shutdown = 1; +static bool keepmuted = 1; +static bool initmute = 1; static int radio_nr = -1; module_param(io, int, 0444); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 3fb76e3834c9..87c1ee13b058 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -23,7 +23,7 @@ static int radio_nr = -1; module_param(radio_nr, int, 0); MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); -static int mono; +static bool mono; module_param(mono, bool, 0); MODULE_PARM_DESC(mono, "Force tuner into mono mode."); diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index d1fab5885061..c54210c7fef9 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -355,17 +355,4 @@ static struct platform_driver radio_si4713_pdriver = { .remove = __exit_p(radio_si4713_pdriver_remove), }; -/* Module Interface */ -static int __init radio_si4713_module_init(void) -{ - return platform_driver_register(&radio_si4713_pdriver); -} - -static void __exit radio_si4713_module_exit(void) -{ - platform_driver_unregister(&radio_si4713_pdriver); -} - -module_init(radio_si4713_module_init); -module_exit(radio_si4713_module_exit); - +module_platform_driver(radio_si4713_pdriver); diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 3e9209f84e09..5d9a90ac3a1c 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -226,20 +226,7 @@ static struct platform_driver timbradio_platform_driver = { .remove = timbradio_remove, }; -/*--------------------------------------------------------------------------*/ - -static int __init timbradio_init(void) -{ - return platform_driver_register(&timbradio_platform_driver); -} - -static void __exit timbradio_exit(void) -{ - platform_driver_unregister(&timbradio_platform_driver); -} - -module_init(timbradio_init); -module_exit(timbradio_exit); +module_platform_driver(timbradio_platform_driver); MODULE_DESCRIPTION("Timberdale Radio driver"); MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 8aa4968d57bc..f1b607099b6c 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2148,8 +2148,6 @@ pdata_err: return r; } -MODULE_ALIAS("platform:wl1273_fm_radio"); - static struct platform_driver wl1273_fm_radio_driver = { .probe = wl1273_fm_radio_probe, .remove = __devexit_p(wl1273_fm_radio_remove), @@ -2159,20 +2157,9 @@ static struct platform_driver wl1273_fm_radio_driver = { }, }; -static int __init wl1273_fm_module_init(void) -{ - pr_info("%s\n", __func__); - return platform_driver_register(&wl1273_fm_radio_driver); -} -module_init(wl1273_fm_module_init); - -static void __exit wl1273_fm_module_exit(void) -{ - platform_driver_unregister(&wl1273_fm_radio_driver); - pr_info(DRIVER_DESC ", Exiting.\n"); -} -module_exit(wl1273_fm_module_exit); +module_platform_driver(wl1273_fm_radio_driver); MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wl1273_fm_radio"); diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 0991e1973678..3408685b690c 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -118,9 +118,11 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) i2cmsg[2] = pll & 0xff; err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg)); - if (!err) - state->freq = f->frequency; - return err; + if (err != sizeof(i2cmsg)) + return err < 0 ? err : -EIO; + + state->freq = f->frequency; + return 0; } static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index 749f67b192e7..86b28579f0c7 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -5,7 +5,7 @@ menu "Texas Instruments WL128x FM driver (ST based)" config RADIO_WL128X tristate "Texas Instruments WL128x FM Radio" depends on VIDEO_V4L2 && RFKILL - select TI_ST + select TI_ST if NET && GPIOLIB help Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 5991ab60303d..bf867a6b5ea0 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -387,7 +387,7 @@ static void send_tasklet(unsigned long arg) * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for * transmission */ -static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, +static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, int payload_len, struct completion *wait_completion) { struct sk_buff *skb; @@ -456,13 +456,13 @@ static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, } /* Sends FM Channel-8 command to the chip and waits for the response */ -u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, +int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, unsigned int payload_len, void *response, int *response_len) { struct sk_buff *skb; struct fm_event_msg_hdr *evt_hdr; unsigned long flags; - u32 ret; + int ret; init_completion(&fmdev->maintask_comp); ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, @@ -470,8 +470,8 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, if (ret) return ret; - ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT)) { fmerr("Timeout(%d sec),didn't get reg" "completion signal from RX tasklet\n", jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); @@ -508,7 +508,7 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, } /* --- Helper functions used in FM interrupt handlers ---*/ -static inline u32 check_cmdresp_status(struct fmdev *fmdev, +static inline int check_cmdresp_status(struct fmdev *fmdev, struct sk_buff **skb) { struct fm_event_msg_hdr *fm_evt_hdr; @@ -1058,7 +1058,7 @@ static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) } /* Returns availability of RDS data in internel buffer */ -u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, +int fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, struct poll_table_struct *pts) { poll_wait(file, &fmdev->rx.rds.read_queue, pts); @@ -1069,7 +1069,7 @@ u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, } /* Copies RDS data from internal buffer to user buffer */ -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, +int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, u8 __user *buf, size_t count) { u32 block_count; @@ -1113,7 +1113,7 @@ u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, return ret; } -u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) +int fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1127,7 +1127,7 @@ u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) } } -u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) +int fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) { if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { fmerr("RX frequency is not set\n"); @@ -1153,7 +1153,7 @@ u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) } -u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) +int fmc_set_region(struct fmdev *fmdev, u8 region_to_set) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1167,7 +1167,7 @@ u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) } } -u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1181,7 +1181,7 @@ u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } } -u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1195,7 +1195,7 @@ u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) } } -u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { switch (fmdev->curr_fmmode) { case FM_MODE_RX: @@ -1210,10 +1210,10 @@ u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) } /* Sends power off command to the chip */ -static u32 fm_power_down(struct fmdev *fmdev) +static int fm_power_down(struct fmdev *fmdev) { u16 payload; - u32 ret; + int ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmerr("FM core is not ready\n"); @@ -1234,7 +1234,7 @@ static u32 fm_power_down(struct fmdev *fmdev) } /* Reads init command from FM firmware file and loads to the chip */ -static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) +static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) { const struct firmware *fw_entry; struct bts_header *fw_header; @@ -1299,7 +1299,7 @@ rel_fw: } /* Loads default RX configuration to the chip */ -static u32 load_default_rx_configuration(struct fmdev *fmdev) +static int load_default_rx_configuration(struct fmdev *fmdev) { int ret; @@ -1311,7 +1311,7 @@ static u32 load_default_rx_configuration(struct fmdev *fmdev) } /* Does FM power on sequence */ -static u32 fm_power_up(struct fmdev *fmdev, u8 mode) +static int fm_power_up(struct fmdev *fmdev, u8 mode) { u16 payload, asic_id, asic_ver; int resp_len, ret; @@ -1374,7 +1374,7 @@ rel: } /* Set FM Modes(TX, RX, OFF) */ -u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) +int fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) { int ret = 0; @@ -1427,7 +1427,7 @@ u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) } /* Returns current FM mode (TX, RX, OFF) */ -u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) +int fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) { if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmerr("FM core is not ready\n"); @@ -1483,10 +1483,10 @@ static void fm_st_reg_comp_cb(void *arg, char data) * This function will be called from FM V4L2 open function. * Register with ST driver and initialize driver data. */ -u32 fmc_prepare(struct fmdev *fmdev) +int fmc_prepare(struct fmdev *fmdev) { static struct st_proto_s fm_st_proto; - u32 ret; + int ret; if (test_bit(FM_CORE_READY, &fmdev->flag)) { fmdbg("FM Core is already up\n"); @@ -1512,10 +1512,8 @@ u32 fmc_prepare(struct fmdev *fmdev) fmdev->streg_cbdata = -EINPROGRESS; fmdbg("%s waiting for ST reg completion signal\n", __func__); - ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, - FM_ST_REG_TIMEOUT); - - if (!ret) { + if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, + FM_ST_REG_TIMEOUT)) { fmerr("Timeout(%d sec), didn't get reg " "completion signal from ST\n", jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); @@ -1589,10 +1587,10 @@ u32 fmc_prepare(struct fmdev *fmdev) * This function will be called from FM V4L2 release function. * Unregister from ST driver. */ -u32 fmc_release(struct fmdev *fmdev) +int fmc_release(struct fmdev *fmdev) { static struct st_proto_s fm_st_proto; - u32 ret; + int ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { fmdbg("FM Core is already down\n"); @@ -1631,7 +1629,7 @@ u32 fmc_release(struct fmdev *fmdev) static int __init fm_drv_init(void) { struct fmdev *fmdev = NULL; - u32 ret = -ENOMEM; + int ret = -ENOMEM; fmdbg("FM driver version %s\n", FM_DRV_VERSION); diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h index aee243bb6630..d9b9c6cf83b4 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.h +++ b/drivers/media/radio/wl128x/fmdrv_common.h @@ -368,27 +368,27 @@ struct fm_event_msg_hdr { #define FM_TX_ANT_IMP_500 2 /* Functions exported by FM common sub-module */ -u32 fmc_prepare(struct fmdev *); -u32 fmc_release(struct fmdev *); +int fmc_prepare(struct fmdev *); +int fmc_release(struct fmdev *); void fmc_update_region_info(struct fmdev *, u8); -u32 fmc_send_cmd(struct fmdev *, u8, u16, +int fmc_send_cmd(struct fmdev *, u8, u16, void *, unsigned int, void *, int *); -u32 fmc_is_rds_data_available(struct fmdev *, struct file *, +int fmc_is_rds_data_available(struct fmdev *, struct file *, struct poll_table_struct *); -u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, +int fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, u8 __user *, size_t); -u32 fmc_set_freq(struct fmdev *, u32); -u32 fmc_set_mode(struct fmdev *, u8); -u32 fmc_set_region(struct fmdev *, u8); -u32 fmc_set_mute_mode(struct fmdev *, u8); -u32 fmc_set_stereo_mono(struct fmdev *, u16); -u32 fmc_set_rds_mode(struct fmdev *, u8); +int fmc_set_freq(struct fmdev *, u32); +int fmc_set_mode(struct fmdev *, u8); +int fmc_set_region(struct fmdev *, u8); +int fmc_set_mute_mode(struct fmdev *, u8); +int fmc_set_stereo_mono(struct fmdev *, u16); +int fmc_set_rds_mode(struct fmdev *, u8); -u32 fmc_get_freq(struct fmdev *, u32 *); -u32 fmc_get_region(struct fmdev *, u8 *); -u32 fmc_get_mode(struct fmdev *, u8 *); +int fmc_get_freq(struct fmdev *, u32 *); +int fmc_get_region(struct fmdev *, u8 *); +int fmc_get_mode(struct fmdev *, u8 *); /* * channel spacing diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index ec529b55b040..43fb72291bea 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -43,12 +43,13 @@ void fm_rx_reset_station_info(struct fmdev *fmdev) fmdev->rx.stat_info.af_list_max = 0; } -u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) +int fm_rx_set_freq(struct fmdev *fmdev, u32 freq) { unsigned long timeleft; u16 payload, curr_frq, intr_flag; u32 curr_frq_in_khz; - u32 ret, resp_len; + u32 resp_len; + int ret; if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { fmerr("Invalid frequency %d\n", freq); @@ -141,10 +142,10 @@ exit: return ret; } -static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) +static int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) { u16 payload; - u32 ret; + int ret; if (spacing > 0 && spacing <= 50000) spacing = FM_CHANNEL_SPACING_50KHZ; @@ -165,7 +166,7 @@ static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) return ret; } -u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, +int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, u32 wrap_around, u32 spacing) { u32 resp_len; @@ -173,7 +174,7 @@ u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, u16 payload, int_reason, intr_flag; u16 offset, space_idx; unsigned long timeleft; - u32 ret; + int ret; /* Set channel spacing */ ret = fm_rx_set_channel_spacing(fmdev, spacing); @@ -296,10 +297,10 @@ again: return ret; } -u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) +int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -322,7 +323,7 @@ u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) } /* Get volume */ -u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) +int fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -338,7 +339,7 @@ u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) } /* To get current band's bottom and top frequency */ -u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) +int fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) { if (bot_freq != NULL) *bot_freq = fmdev->rx.region.bot_freq; @@ -356,11 +357,11 @@ void fm_rx_get_region(struct fmdev *fmdev, u8 *region) } /* Sets band (0-Europe/US; 1-Japan) */ -u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) +int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) { u16 payload; u32 new_frq = 0; - u32 ret; + int ret; if (region_to_set != FM_BAND_EUROPE_US && region_to_set != FM_BAND_JAPAN) { @@ -399,7 +400,7 @@ u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) } /* Reads current mute mode (Mute Off/On/Attenuate)*/ -u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) +int fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -414,10 +415,10 @@ u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) return 0; } -static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) +static int fm_config_rx_mute_reg(struct fmdev *fmdev) { u16 payload, muteval; - u32 ret; + int ret; muteval = 0; switch (fmdev->rx.mute_mode) { @@ -448,10 +449,10 @@ static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) } /* Configures mute mode (Mute Off/On/Attenuate) */ -u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { u8 org_state; - u32 ret; + int ret; if (fmdev->rx.mute_mode == mute_mode_toset) return 0; @@ -469,7 +470,7 @@ u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } /* Gets RF dependent soft mute mode enable/disable status */ -u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) +int fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -485,10 +486,10 @@ u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) } /* Sets RF dependent soft mute mode */ -u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) +int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) { u8 org_state; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -514,11 +515,11 @@ u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) } /* Returns the signal strength level of current channel */ -u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) +int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) { u16 curr_rssi_lel; u32 resp_len; - u32 ret; + int ret; if (rssilvl == NULL) { fmerr("Invalid memory\n"); @@ -539,10 +540,10 @@ u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) * Sets the signal strength level that once reached * will stop the auto search process */ -u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) +int fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) { u16 payload; - u32 ret; + int ret; if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { @@ -561,7 +562,7 @@ u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) } /* Returns current RX RSSI threshold value */ -u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) +int fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -577,10 +578,10 @@ u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) } /* Sets RX stereo/mono modes */ -u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { fmerr("Invalid mode\n"); @@ -605,10 +606,11 @@ u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) } /* Gets current RX stereo/mono mode */ -u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) +int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) { u16 curr_mode; - u32 ret, resp_len; + u32 resp_len; + int ret; if (mode == NULL) { fmerr("Invalid memory\n"); @@ -626,10 +628,10 @@ u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) } /* Choose RX de-emphasis filter mode (50us/75us) */ -u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) +int fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -652,7 +654,7 @@ u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) } /* Gets current RX de-emphasis filter mode */ -u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) +int fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -668,10 +670,10 @@ u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) } /* Enable/Disable RX RDS */ -u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { u16 payload; - u32 ret; + int ret; if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { fmerr("Invalid rds option\n"); @@ -743,7 +745,7 @@ u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) } /* Returns current RX RDS enable/disable status */ -u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) +int fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -759,10 +761,10 @@ u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) } /* Sets RDS operation mode (RDS/RDBS) */ -u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) +int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -784,7 +786,7 @@ u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) } /* Returns current RDS operation mode */ -u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) +int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -800,10 +802,10 @@ u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) } /* Configures Alternate Frequency switch mode */ -u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) +int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; @@ -831,7 +833,7 @@ u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) } /* Returns Alternate Frequency switch status */ -u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) +int fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) { if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h index 329e62f6be76..32add81f8d87 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.h +++ b/drivers/media/radio/wl128x/fmdrv_rx.h @@ -22,38 +22,38 @@ #ifndef _FMDRV_RX_H #define _FMDRV_RX_H -u32 fm_rx_set_freq(struct fmdev *, u32); -u32 fm_rx_set_mute_mode(struct fmdev *, u8); -u32 fm_rx_set_stereo_mono(struct fmdev *, u16); -u32 fm_rx_set_rds_mode(struct fmdev *, u8); -u32 fm_rx_set_rds_system(struct fmdev *, u8); -u32 fm_rx_set_volume(struct fmdev *, u16); -u32 fm_rx_set_rssi_threshold(struct fmdev *, short); -u32 fm_rx_set_region(struct fmdev *, u8); -u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8); -u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16); -u32 fm_rx_set_af_switch(struct fmdev *, u8); +int fm_rx_set_freq(struct fmdev *, u32); +int fm_rx_set_mute_mode(struct fmdev *, u8); +int fm_rx_set_stereo_mono(struct fmdev *, u16); +int fm_rx_set_rds_mode(struct fmdev *, u8); +int fm_rx_set_rds_system(struct fmdev *, u8); +int fm_rx_set_volume(struct fmdev *, u16); +int fm_rx_set_rssi_threshold(struct fmdev *, short); +int fm_rx_set_region(struct fmdev *, u8); +int fm_rx_set_rfdepend_softmute(struct fmdev *, u8); +int fm_rx_set_deemphasis_mode(struct fmdev *, u16); +int fm_rx_set_af_switch(struct fmdev *, u8); void fm_rx_reset_rds_cache(struct fmdev *); void fm_rx_reset_station_info(struct fmdev *); -u32 fm_rx_seek(struct fmdev *, u32, u32, u32); +int fm_rx_seek(struct fmdev *, u32, u32, u32); -u32 fm_rx_get_rds_mode(struct fmdev *, u8 *); -u32 fm_rx_get_rds_system(struct fmdev *, u8 *); -u32 fm_rx_get_mute_mode(struct fmdev *, u8 *); -u32 fm_rx_get_volume(struct fmdev *, u16 *); -u32 fm_rx_get_band_freq_range(struct fmdev *, +int fm_rx_get_rds_mode(struct fmdev *, u8 *); +int fm_rx_get_rds_system(struct fmdev *, u8 *); +int fm_rx_get_mute_mode(struct fmdev *, u8 *); +int fm_rx_get_volume(struct fmdev *, u16 *); +int fm_rx_get_band_freq_range(struct fmdev *, u32 *, u32 *); -u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_level(struct fmdev *, u16 *); -u32 fm_rx_get_rssi_threshold(struct fmdev *, short *); -u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); -u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *); -u32 fm_rx_get_af_switch(struct fmdev *, u8 *); +int fm_rx_get_stereo_mono(struct fmdev *, u16 *); +int fm_rx_get_rssi_level(struct fmdev *, u16 *); +int fm_rx_get_rssi_threshold(struct fmdev *, short *); +int fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); +int fm_rx_get_deemph_mode(struct fmdev *, u16 *); +int fm_rx_get_af_switch(struct fmdev *, u8 *); void fm_rx_get_region(struct fmdev *, u8 *); -u32 fm_rx_set_chanl_spacing(struct fmdev *, u8); -u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *); +int fm_rx_set_chanl_spacing(struct fmdev *, u8); +int fm_rx_get_chanl_spacing(struct fmdev *, u8 *); #endif diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c index be54068b56a8..6ea33e09d63b 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.c +++ b/drivers/media/radio/wl128x/fmdrv_tx.c @@ -24,10 +24,10 @@ #include "fmdrv_common.h" #include "fmdrv_tx.h" -u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +int fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) { u16 payload; - u32 ret; + int ret; if (fmdev->tx_data.aud_mode == mode) return 0; @@ -46,10 +46,10 @@ u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) return ret; } -static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) +static int set_rds_text(struct fmdev *fmdev, u8 *rds_text) { u16 payload; - u32 ret; + int ret; ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, strlen(rds_text), NULL, NULL); @@ -66,10 +66,10 @@ static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) return 0; } -static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) +static int set_rds_data_mode(struct fmdev *fmdev, u8 mode) { u16 payload; - u32 ret; + int ret; /* Setting unique PI TODO: how unique? */ payload = (u16)0xcafe; @@ -89,10 +89,10 @@ static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) return 0; } -static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) +static int set_rds_len(struct fmdev *fmdev, u8 type, u16 len) { u16 payload; - u32 ret; + int ret; len |= type << 8; payload = len; @@ -105,10 +105,10 @@ static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) return 0; } -u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +int fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) { u16 payload; - u32 ret; + int ret; u8 rds_text[] = "Zoom2\n"; fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, @@ -148,10 +148,10 @@ u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) return 0; } -u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) +int fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -176,10 +176,10 @@ u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) return 0; } -u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) +int fm_tx_set_af(struct fmdev *fmdev, u32 af) { u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -196,10 +196,10 @@ u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) return 0; } -u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) +int fm_tx_set_region(struct fmdev *fmdev, u8 region) { u16 payload; - u32 ret; + int ret; if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { fmerr("Invalid band\n"); @@ -216,10 +216,10 @@ u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) return 0; } -u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +int fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) { u16 payload; - u32 ret; + int ret; fmdbg("tx: mute mode %d\n", mute_mode_toset); @@ -233,11 +233,11 @@ u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) } /* Set TX Audio I/O */ -static u32 set_audio_io(struct fmdev *fmdev) +static int set_audio_io(struct fmdev *fmdev) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload; - u32 ret; + int ret; /* Set Audio I/O Enable */ payload = tx->audio_io; @@ -251,12 +251,12 @@ static u32 set_audio_io(struct fmdev *fmdev) } /* Start TX Transmission */ -static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) +static int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) { struct fmtx_data *tx = &fmdev->tx_data; unsigned long timeleft; u16 payload; - u32 ret; + int ret; /* Enable POWER_ENB interrupts */ payload = FM_POW_ENB_EVENT; @@ -289,11 +289,11 @@ static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) } /* Set TX power level */ -u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) +int fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) { u16 payload; struct fmtx_data *tx = &fmdev->tx_data; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -328,11 +328,11 @@ u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) * Convert V4L2 specified filter values to chip specific filter values. */ -u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) +int fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload; - u32 ret; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -360,10 +360,11 @@ u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) } /* Get the TX tuning capacitor value.*/ -u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) +int fm_tx_get_tune_cap_val(struct fmdev *fmdev) { u16 curr_val; - u32 ret, resp_len; + u32 resp_len; + int ret; if (fmdev->curr_fmmode != FM_MODE_TX) return -EPERM; @@ -379,11 +380,11 @@ u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) } /* Set TX Frequency */ -u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) +int fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) { struct fmtx_data *tx = &fmdev->tx_data; u16 payload, chanl_index; - u32 ret; + int ret; if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { enable_xmit(fmdev, 0); diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h index e393a2bdd49e..11ae2e4c2d03 100644 --- a/drivers/media/radio/wl128x/fmdrv_tx.h +++ b/drivers/media/radio/wl128x/fmdrv_tx.h @@ -22,16 +22,16 @@ #ifndef _FMDRV_TX_H #define _FMDRV_TX_H -u32 fm_tx_set_freq(struct fmdev *, u32); -u32 fm_tx_set_pwr_lvl(struct fmdev *, u8); -u32 fm_tx_set_region(struct fmdev *, u8); -u32 fm_tx_set_mute_mode(struct fmdev *, u8); -u32 fm_tx_set_stereo_mono(struct fmdev *, u16); -u32 fm_tx_set_rds_mode(struct fmdev *, u8); -u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8); -u32 fm_tx_set_af(struct fmdev *, u32); -u32 fm_tx_set_preemph_filter(struct fmdev *, u32); -u32 fm_tx_get_tune_cap_val(struct fmdev *); +int fm_tx_set_freq(struct fmdev *, u32); +int fm_tx_set_pwr_lvl(struct fmdev *, u8); +int fm_tx_set_region(struct fmdev *, u8); +int fm_tx_set_mute_mode(struct fmdev *, u8); +int fm_tx_set_stereo_mono(struct fmdev *, u16); +int fm_tx_set_rds_mode(struct fmdev *, u8); +int fm_tx_set_radio_text(struct fmdev *, u8 *, u8); +int fm_tx_set_af(struct fmdev *, u32); +int fm_tx_set_preemph_filter(struct fmdev *, u32); +int fm_tx_get_tune_cap_val(struct fmdev *); #endif diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 4f5c43d2566c..077d369a0173 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -84,6 +84,7 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, struct fmdev *fmdev; ret = copy_from_user(&rds, buf, sizeof(rds)); + rds.text[sizeof(rds.text) - 1] = '\0'; fmdbg("(%d)type: %d, text %s, af %d\n", ret, rds.text_type, rds.text, rds.af_freq); if (ret) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index aeb7f43dfb65..4df4affeea5f 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -87,6 +87,16 @@ config IR_RC5_SZ_DECODER uses an IR protocol that is almost standard RC-5, but not quite, as it uses an additional bit). +config IR_SANYO_DECODER + tristate "Enable IR raw decoder for the Sanyo protocol" + depends on RC_CORE + default y + + ---help--- + Enable this option if you have an infrared remote control which + uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), + and you need software decoding support. + config IR_MCE_KBD_DECODER tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 2156e786b557..fb3dee2dd845 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o +obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 17f8db00435a..3c9431a9f62d 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -194,8 +194,8 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) return 0; } - IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n", - data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 2e5cd3100b64..95e630998aaf 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -357,6 +357,7 @@ static void init_decoders(struct work_struct *work) load_rc6_decode(); load_jvc_decode(); load_sony_decode(); + load_sanyo_decode(); load_mce_kbd_decode(); load_lirc_codec(); diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 140fb67e2f89..4cfdd7fa4bbd 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -18,24 +18,31 @@ /* * This decoder currently supports: * RC6-0-16 (standard toggle bit in header) + * RC6-6A-20 (no toggle bit) * RC6-6A-24 (no toggle bit) * RC6-6A-32 (MCE version with toggle bit in body) */ -#define RC6_UNIT 444444 /* us */ +#define RC6_UNIT 444444 /* nanosecs */ #define RC6_HEADER_NBITS 4 /* not including toggle bit */ #define RC6_0_NBITS 16 -#define RC6_6A_SMALL_NBITS 24 -#define RC6_6A_LARGE_NBITS 32 +#define RC6_6A_32_NBITS 32 +#define RC6_6A_NBITS 128 /* Variable 8..128 */ #define RC6_PREFIX_PULSE (6 * RC6_UNIT) #define RC6_PREFIX_SPACE (2 * RC6_UNIT) #define RC6_BIT_START (1 * RC6_UNIT) #define RC6_BIT_END (1 * RC6_UNIT) #define RC6_TOGGLE_START (2 * RC6_UNIT) #define RC6_TOGGLE_END (2 * RC6_UNIT) +#define RC6_SUFFIX_SPACE (6 * RC6_UNIT) #define RC6_MODE_MASK 0x07 /* for the header bits */ #define RC6_STARTBIT_MASK 0x08 /* for the header bits */ #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ +#define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */ +#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */ +#ifndef CHAR_BIT +#define CHAR_BIT 8 /* Normally in <limits.h> */ +#endif enum rc6_mode { RC6_MODE_0, @@ -125,6 +132,7 @@ again: break; data->state = STATE_HEADER_BIT_START; + data->header = 0; return 0; case STATE_HEADER_BIT_START: @@ -171,20 +179,14 @@ again: data->state = STATE_BODY_BIT_START; decrease_duration(&ev, RC6_TOGGLE_END); data->count = 0; + data->body = 0; switch (rc6_mode(data)) { case RC6_MODE_0: data->wanted_bits = RC6_0_NBITS; break; case RC6_MODE_6A: - /* This might look weird, but we basically - check the value of the first body bit to - determine the number of bits in mode 6A */ - if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) || - geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) - data->wanted_bits = RC6_6A_LARGE_NBITS; - else - data->wanted_bits = RC6_6A_SMALL_NBITS; + data->wanted_bits = RC6_6A_NBITS; break; default: IR_dprintk(1, "RC6 unknown mode\n"); @@ -193,15 +195,21 @@ again: goto again; case STATE_BODY_BIT_START: - if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) - break; - - data->body <<= 1; - if (ev.pulse) - data->body |= 1; - data->count++; - data->state = STATE_BODY_BIT_END; - return 0; + if (eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2)) { + /* Discard LSB's that won't fit in data->body */ + if (data->count++ < CHAR_BIT * sizeof data->body) { + data->body <<= 1; + if (ev.pulse) + data->body |= 1; + } + data->state = STATE_BODY_BIT_END; + return 0; + } else if (RC6_MODE_6A == rc6_mode(data) && !ev.pulse && + geq_margin(ev.duration, RC6_SUFFIX_SPACE, RC6_UNIT / 2)) { + data->state = STATE_FINISHED; + goto again; + } + break; case STATE_BODY_BIT_END: if (!is_transition(&ev, &dev->raw->prev_ev)) @@ -221,20 +229,27 @@ again: switch (rc6_mode(data)) { case RC6_MODE_0: - scancode = data->body & 0xffff; + scancode = data->body; toggle = data->toggle; IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n", scancode, toggle); break; case RC6_MODE_6A: - if (data->wanted_bits == RC6_6A_LARGE_NBITS) { - toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0; - scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK; + if (data->count > CHAR_BIT * sizeof data->body) { + IR_dprintk(1, "RC6 too many (%u) data bits\n", + data->count); + goto out; + } + + scancode = data->body; + if (data->count == RC6_6A_32_NBITS && + (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { + /* MCE RC */ + toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0; + scancode &= ~RC6_6A_MCE_TOGGLE_MASK; } else { toggle = 0; - scancode = data->body & 0xffffff; } - IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n", scancode, toggle); break; diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c new file mode 100644 index 000000000000..d38fbdd0b25a --- /dev/null +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -0,0 +1,205 @@ +/* ir-sanyo-decoder.c - handle SANYO IR Pulse/Space protocol + * + * Copyright (C) 2011 by Mauro Carvalho Chehab <mchehab@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * 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. + * + * This protocol uses the NEC protocol timings. However, data is formatted as: + * 13 bits Custom Code + * 13 bits NOT(Custom Code) + * 8 bits Key data + * 8 bits NOT(Key data) + * + * According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon + * Information for this protocol is available at the Sanyo LC7461 datasheet. + */ + +#include <linux/module.h> +#include <linux/bitrev.h> +#include "rc-core-priv.h" + +#define SANYO_NBITS (13+13+8+8) +#define SANYO_UNIT 562500 /* ns */ +#define SANYO_HEADER_PULSE (16 * SANYO_UNIT) +#define SANYO_HEADER_SPACE (8 * SANYO_UNIT) +#define SANYO_BIT_PULSE (1 * SANYO_UNIT) +#define SANYO_BIT_0_SPACE (1 * SANYO_UNIT) +#define SANYO_BIT_1_SPACE (3 * SANYO_UNIT) +#define SANYO_REPEAT_SPACE (150 * SANYO_UNIT) +#define SANYO_TRAILER_PULSE (1 * SANYO_UNIT) +#define SANYO_TRAILER_SPACE (10 * SANYO_UNIT) /* in fact, 42 */ + +enum sanyo_state { + STATE_INACTIVE, + STATE_HEADER_SPACE, + STATE_BIT_PULSE, + STATE_BIT_SPACE, + STATE_TRAILER_PULSE, + STATE_TRAILER_SPACE, +}; + +/** + * ir_sanyo_decode() - Decode one SANYO pulse or space + * @dev: the struct rc_dev descriptor of the device + * @duration: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct sanyo_dec *data = &dev->raw->sanyo; + u32 scancode; + u8 address, not_address, command, not_command; + + if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO)) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) { + IR_dprintk(1, "SANYO event reset received. reset to state 0\n"); + data->state = STATE_INACTIVE; + } + return 0; + } + + IR_dprintk(2, "SANYO decode started at state %d (%uus %s)\n", + data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + + switch (data->state) { + + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (eq_margin(ev.duration, SANYO_HEADER_PULSE, SANYO_UNIT / 2)) { + data->count = 0; + data->state = STATE_HEADER_SPACE; + return 0; + } + break; + + + case STATE_HEADER_SPACE: + if (ev.pulse) + break; + + if (eq_margin(ev.duration, SANYO_HEADER_SPACE, SANYO_UNIT / 2)) { + data->state = STATE_BIT_PULSE; + return 0; + } + + break; + + case STATE_BIT_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SANYO_BIT_PULSE, SANYO_UNIT / 2)) + break; + + data->state = STATE_BIT_SPACE; + return 0; + + case STATE_BIT_SPACE: + if (ev.pulse) + break; + + if (!data->count && geq_margin(ev.duration, SANYO_REPEAT_SPACE, SANYO_UNIT / 2)) { + if (!dev->keypressed) { + IR_dprintk(1, "SANYO discarding last key repeat: event after key up\n"); + } else { + rc_repeat(dev); + IR_dprintk(1, "SANYO repeat last key\n"); + data->state = STATE_INACTIVE; + } + return 0; + } + + data->bits <<= 1; + if (eq_margin(ev.duration, SANYO_BIT_1_SPACE, SANYO_UNIT / 2)) + data->bits |= 1; + else if (!eq_margin(ev.duration, SANYO_BIT_0_SPACE, SANYO_UNIT / 2)) + break; + data->count++; + + if (data->count == SANYO_NBITS) + data->state = STATE_TRAILER_PULSE; + else + data->state = STATE_BIT_PULSE; + + return 0; + + case STATE_TRAILER_PULSE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, SANYO_TRAILER_PULSE, SANYO_UNIT / 2)) + break; + + data->state = STATE_TRAILER_SPACE; + return 0; + + case STATE_TRAILER_SPACE: + if (ev.pulse) + break; + + if (!geq_margin(ev.duration, SANYO_TRAILER_SPACE, SANYO_UNIT / 2)) + break; + + address = bitrev16((data->bits >> 29) & 0x1fff) >> 3; + not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3; + command = bitrev8((data->bits >> 8) & 0xff); + not_command = bitrev8((data->bits >> 0) & 0xff); + + if ((command ^ not_command) != 0xff) { + IR_dprintk(1, "SANYO checksum error: received 0x%08Lx\n", + data->bits); + data->state = STATE_INACTIVE; + return 0; + } + + scancode = address << 8 | command; + IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode); + rc_keydown(dev, scancode, 0); + data->state = STATE_INACTIVE; + return 0; + } + + IR_dprintk(1, "SANYO decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static struct ir_raw_handler sanyo_handler = { + .protocols = RC_TYPE_SANYO, + .decode = ir_sanyo_decode, +}; + +static int __init ir_sanyo_decode_init(void) +{ + ir_raw_handler_register(&sanyo_handler); + + printk(KERN_INFO "IR SANYO protocol handler initialized\n"); + return 0; +} + +static void __exit ir_sanyo_decode_exit(void) +{ + ir_raw_handler_unregister(&sanyo_handler); +} + +module_init(ir_sanyo_decode_init); +module_exit(ir_sanyo_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); +MODULE_DESCRIPTION("SANYO IR protocol decoder"); diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index e51c6163378b..929bbbc16393 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -183,6 +183,57 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1d3f, KEY_HOME }, /* + * Keycodes for PT# R-005 remote bundled with Haupauge HVR-930C + * Keycodes start with address = 0x1c + */ + { 0x1c3b, KEY_GOTO }, + { 0x1c3d, KEY_POWER }, + + { 0x1c14, KEY_UP }, + { 0x1c15, KEY_DOWN }, + { 0x1c16, KEY_LEFT }, + { 0x1c17, KEY_RIGHT }, + { 0x1c25, KEY_OK }, + + { 0x1c00, KEY_0 }, + { 0x1c01, KEY_1 }, + { 0x1c02, KEY_2 }, + { 0x1c03, KEY_3 }, + { 0x1c04, KEY_4 }, + { 0x1c05, KEY_5 }, + { 0x1c06, KEY_6 }, + { 0x1c07, KEY_7 }, + { 0x1c08, KEY_8 }, + { 0x1c09, KEY_9 }, + + { 0x1c1f, KEY_EXIT }, /* BACK */ + { 0x1c0d, KEY_MENU }, + { 0x1c1c, KEY_TV }, + + { 0x1c10, KEY_VOLUMEUP }, + { 0x1c11, KEY_VOLUMEDOWN }, + + { 0x1c20, KEY_CHANNELUP }, + { 0x1c21, KEY_CHANNELDOWN }, + + { 0x1c0f, KEY_MUTE }, + { 0x1c12, KEY_PREVIOUS }, /* Prev */ + + { 0x1c36, KEY_STOP }, + { 0x1c37, KEY_RECORD }, + + { 0x1c24, KEY_LAST }, /* <| */ + { 0x1c1e, KEY_NEXT }, /* >| */ + + { 0x1c0a, KEY_TEXT }, + { 0x1c0e, KEY_SUBTITLE }, /* CC */ + + { 0x1c32, KEY_REWIND }, + { 0x1c30, KEY_PAUSE }, + { 0x1c35, KEY_PLAY }, + { 0x1c34, KEY_FASTFORWARD }, + + /* * Keycodes for the old Black Remote Controller * This one also uses RC-5 protocol * Keycodes start with address = 0x00 diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index 3bd1de1f585c..23ee05e53949 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -1,4 +1,4 @@ -/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller +/* videomate-k100.h - Keytable for videomate_k100 Remote Controller * * keymap imported from ir-keymaps.c * @@ -13,7 +13,7 @@ #include <media/rc-map.h> #include <linux/module.h> -static struct rc_map_table videomate_m1f[] = { +static struct rc_map_table videomate_k100[] = { { 0x01, KEY_POWER }, { 0x31, KEY_TUNER }, { 0x33, KEY_VIDEO }, @@ -67,27 +67,27 @@ static struct rc_map_table videomate_m1f[] = { { 0x18, KEY_TEXT }, }; -static struct rc_map_list videomate_m1f_map = { +static struct rc_map_list videomate_k100_map = { .map = { - .scan = videomate_m1f, - .size = ARRAY_SIZE(videomate_m1f), + .scan = videomate_k100, + .size = ARRAY_SIZE(videomate_k100), .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_VIDEOMATE_M1F, + .name = RC_MAP_VIDEOMATE_K100, } }; -static int __init init_rc_map_videomate_m1f(void) +static int __init init_rc_map_videomate_k100(void) { - return rc_map_register(&videomate_m1f_map); + return rc_map_register(&videomate_k100_map); } -static void __exit exit_rc_map_videomate_m1f(void) +static void __exit exit_rc_map_videomate_k100(void) { - rc_map_unregister(&videomate_m1f_map); + rc_map_unregister(&videomate_k100_map); } -module_init(init_rc_map_videomate_m1f) -module_exit(exit_rc_map_videomate_m1f) +module_init(init_rc_map_videomate_k100) +module_exit(exit_rc_map_videomate_k100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 27997a9ceb0d..ca12d3289bfe 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -38,7 +38,7 @@ #include <media/lirc.h> #include <media/lirc_dev.h> -static int debug; +static bool debug; #define IRCTL_DEV_NAME "BaseRemoteCtl" #define NOPLUG -1 diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 20bb12d6fbbe..21105bf9594d 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -156,9 +156,9 @@ /* module parameters */ #ifdef CONFIG_USB_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif #define mce_dbg(dev, fmt, ...) \ diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index c6ca870e8b7e..b72f8580e317 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -84,6 +84,11 @@ struct ir_raw_event_ctrl { unsigned count; unsigned wanted_bits; } rc5_sz; + struct sanyo_dec { + int state; + unsigned count; + u64 bits; + } sanyo; struct mce_kbd_dec { struct input_dev *idev; struct timer_list rx_timeout; @@ -193,6 +198,13 @@ static inline void load_jvc_decode(void) { } static inline void load_sony_decode(void) { } #endif +/* from ir-sanyo-decoder.c */ +#ifdef CONFIG_IR_SANYO_DECODER_MODULE +#define load_sanyo_decode() request_module("ir-sanyo-decoder") +#else +static inline void load_sanyo_decode(void) { } +#endif + /* from ir-mce_kbd-decoder.c */ #ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE #define load_mce_kbd_decode() request_module("ir-mce_kbd-decoder") diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f5db8b949bc3..f6a930b70c69 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -736,6 +736,7 @@ static struct { { RC_TYPE_JVC, "jvc" }, { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, + { RC_TYPE_SANYO, "sanyo" }, { RC_TYPE_MCE_KBD, "mce_kbd" }, { RC_TYPE_LIRC, "lirc" }, { RC_TYPE_OTHER, "other" }, diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 07322fb75eff..ad95c67a4dba 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -286,12 +286,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3) rr3_ftr(rr3->dev, "Entering %s\n", __func__); - if (!rr3->det_enabled) { - dev_warn(rr3->dev, "not issuing async read, " - "detector not enabled\n"); - return; - } - memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize); res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); if (res) @@ -827,6 +821,7 @@ out: static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) { struct redrat3_dev *rr3; + int ret; if (!urb) return; @@ -840,15 +835,13 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) rr3_ftr(rr3->dev, "Entering %s\n", __func__); - if (!rr3->det_enabled) { - rr3_dbg(rr3->dev, "received a read callback but detector " - "disabled - ignoring\n"); - return; - } - switch (urb->status) { case 0: - redrat3_get_ir_data(rr3, urb->actual_length); + ret = redrat3_get_ir_data(rr3, urb->actual_length); + if (!ret) { + /* no error, prepare to read more */ + redrat3_issue_async(rr3); + } break; case -ECONNRESET: @@ -865,11 +858,6 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) rr3->pkttype = 0; break; } - - if (!rr3->transmitting) - redrat3_issue_async(rr3); - else - rr3_dbg(rr3->dev, "IR transmit in progress\n"); } static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs) @@ -896,21 +884,24 @@ static u16 mod_freq_to_val(unsigned int mod_freq) return (u16)(65536 - (mult / mod_freq)); } -static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier) +static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) { - struct redrat3_dev *rr3 = dev->priv; + struct redrat3_dev *rr3 = rcdev->priv; + struct device *dev = rr3->dev; + rr3_dbg(dev, "Setting modulation frequency to %u", carrier); rr3->carrier = carrier; return carrier; } -static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) +static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, + unsigned count) { struct redrat3_dev *rr3 = rcdev->priv; struct device *dev = rr3->dev; struct redrat3_signal_header header; - int i, j, count, ret, ret_len, offset; + int i, j, ret, ret_len, offset; int lencheck, cur_sample_len, pipe; char *buffer = NULL, *sigdata = NULL; int *sample_lens = NULL; @@ -928,20 +919,13 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) return -EAGAIN; } - count = n / sizeof(int); if (count > (RR3_DRIVER_MAXLENS * 2)) return -EINVAL; + /* rr3 will disable rc detector on transmit */ + rr3->det_enabled = false; rr3->transmitting = true; - redrat3_disable_detector(rr3); - - if (rr3->det_enabled) { - dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__); - ret = -EIO; - goto out; - } - sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); if (!sample_lens) { ret = -ENOMEM; @@ -1055,7 +1039,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n) if (ret < 0) dev_err(dev, "Error: control msg send failed, rc %d\n", ret); else - ret = n; + ret = count; out: kfree(sample_lens); @@ -1063,8 +1047,8 @@ out: kfree(sigdata); rr3->transmitting = false; - - redrat3_enable_detector(rr3); + /* rr3 re-enables rc detector because it was enabled before */ + rr3->det_enabled = true; return ret; } diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index b1d29d09eeae..d6f4bfe09391 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -43,9 +43,9 @@ #define DRIVER_DESC "Streamzap Remote Control driver" #ifdef CONFIG_USB_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif #define USB_STREAMZAP_VENDOR_ID 0x0e9c diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index e7f7a57bf684..b09c5fae489b 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -226,11 +226,11 @@ module_param(protocol, uint, 0444); MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command " "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); -static int invert; /* default = 0 */ +static bool invert; /* default = 0 */ module_param(invert, bool, 0444); MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver"); -static int txandrx; /* default = 0 */ +static bool txandrx; /* default = 0 */ module_param(txandrx, bool, 0444); MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX"); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b303a3f8a9f8..9adada0d7447 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -533,6 +533,13 @@ config VIDEO_ADP1653 This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. +config VIDEO_AS3645A + tristate "AS3645A flash driver support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + ---help--- + This is a driver for the AS3645A and LM3555 flash controllers. It has + build in control for flash, torch and indicator LEDs. + comment "Video improvement chips" config VIDEO_UPD64031A @@ -580,25 +587,6 @@ config VIDEO_M52790 endmenu # encoder / decoder chips -config VIDEO_SH_VOU - tristate "SuperH VOU video output driver" - depends on VIDEO_DEV && ARCH_SHMOBILE - select VIDEOBUF_DMA_CONTIG - help - Support for the Video Output Unit (VOU) on SuperH SoCs. - -config VIDEO_VIU - tristate "Freescale VIU Video Driver" - depends on VIDEO_V4L2 && PPC_MPC512x - select VIDEOBUF_DMA_CONTIG - default y - ---help--- - Support for Freescale VIU video driver. This device captures - video data, or overlays video on DIU frame buffer. - - Say Y here if you want to enable VIU device on MPC5121e Rev2+. - In doubt, say N. - config VIDEO_VIVI tristate "Virtual Video Driver" depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 @@ -613,66 +601,130 @@ config VIDEO_VIVI Say Y here if you want to test video apps or debug V4L devices. In doubt, say N. -source "drivers/media/video/davinci/Kconfig" +# +# USB Multimedia device configuration +# -source "drivers/media/video/omap/Kconfig" +menuconfig V4L_USB_DRIVERS + bool "V4L USB devices" + depends on USB + default y -source "drivers/media/video/bt8xx/Kconfig" +if V4L_USB_DRIVERS -config VIDEO_PMS - tristate "Mediavision Pro Movie Studio Video For Linux" - depends on ISA && VIDEO_V4L2 - help - Say Y if you have such a thing. +source "drivers/media/video/uvc/Kconfig" + +source "drivers/media/video/gspca/Kconfig" + +source "drivers/media/video/pvrusb2/Kconfig" + +source "drivers/media/video/hdpvr/Kconfig" + +source "drivers/media/video/em28xx/Kconfig" + +source "drivers/media/video/tlg2300/Kconfig" + +source "drivers/media/video/cx231xx/Kconfig" + +source "drivers/media/video/tm6000/Kconfig" + +source "drivers/media/video/usbvision/Kconfig" + +source "drivers/media/video/et61x251/Kconfig" + +source "drivers/media/video/sn9c102/Kconfig" + +source "drivers/media/video/pwc/Kconfig" + +source "drivers/media/video/cpia2/Kconfig" + +config USB_ZR364XX + tristate "USB ZR364XX Camera support" + depends on VIDEO_V4L2 + select VIDEOBUF_GEN + select VIDEOBUF_VMALLOC + ---help--- + Say Y here if you want to connect this type of camera to your + computer's USB port. + See <file:Documentation/video4linux/zr364xx.txt> for more info + and list of supported cameras. To compile this driver as a module, choose M here: the - module will be called pms. + module will be called zr364xx. -config VIDEO_BWQCAM - tristate "Quickcam BW Video For Linux" - depends on PARPORT && VIDEO_V4L2 - help - Say Y have if you the black and white version of the QuickCam - camera. See the next option for the color version. +config USB_STKWEBCAM + tristate "USB Syntek DC1125 Camera support" + depends on VIDEO_V4L2 && EXPERIMENTAL + ---help--- + Say Y here if you want to use this type of camera. + Supported devices are typically found in some Asus laptops, + with USB id 174f:a311 and 05e1:0501. Other Syntek cameras + may be supported by the stk11xx driver, from which this is + derived, see <http://sourceforge.net/projects/syntekdriver/> To compile this driver as a module, choose M here: the - module will be called bw-qcam. + module will be called stkwebcam. -config VIDEO_CQCAM - tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)" - depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2 +config USB_S2255 + tristate "USB Sensoray 2255 video capture device" + depends on VIDEO_V4L2 + select VIDEOBUF_VMALLOC + default n help - This is the video4linux driver for the colour version of the - Connectix QuickCam. If you have one of these cameras, say Y here, - otherwise say N. This driver does not work with the original - monochrome QuickCam, QuickCam VC or QuickClip. It is also available - as a module (c-qcam). - Read <file:Documentation/video4linux/CQcam.txt> for more information. + Say Y here if you want support for the Sensoray 2255 USB device. + This driver can be compiled as a module, called s2255drv. -config VIDEO_W9966 - tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" - depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 - help - Video4linux driver for Winbond's w9966 based Webcams. - Currently tested with the LifeView FlyCam Supra. - If you have one of these cameras, say Y here - otherwise say N. - This driver is also available as a module (w9966). +endif # V4L_USB_DRIVERS - Check out <file:Documentation/video4linux/w9966.txt> for more - information. +# +# PCI drivers configuration +# -source "drivers/media/video/cpia2/Kconfig" +menuconfig V4L_PCI_DRIVERS + bool "V4L PCI(e) devices" + depends on PCI + default y + ---help--- + Say Y here to enable support for these PCI(e) drivers. -config VIDEO_VINO - tristate "SGI Vino Video For Linux (EXPERIMENTAL)" - depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 - select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO - help - Say Y here to build in support for the Vino video input system found - on SGI Indy machines. +if V4L_PCI_DRIVERS -source "drivers/media/video/zoran/Kconfig" +source "drivers/media/video/au0828/Kconfig" + +source "drivers/media/video/bt8xx/Kconfig" + +source "drivers/media/video/cx18/Kconfig" + +source "drivers/media/video/cx23885/Kconfig" + +source "drivers/media/video/cx25821/Kconfig" + +source "drivers/media/video/cx88/Kconfig" + +config VIDEO_HEXIUM_GEMINI + tristate "Hexium Gemini frame grabber" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + ---help--- + This is a video4linux driver for the Hexium Gemini frame + grabber card by Hexium. Please note that the Gemini Dual + card is *not* fully supported. + + To compile this driver as a module, choose M here: the + module will be called hexium_gemini. + +config VIDEO_HEXIUM_ORION + tristate "Hexium HV-PCI6 and Orion frame grabber" + depends on PCI && VIDEO_V4L2 && I2C + select VIDEO_SAA7146_VV + ---help--- + This is a video4linux driver for the Hexium HV-PCI6 and + Orion frame grabber cards by Hexium. + + To compile this driver as a module, choose M here: the + module will be called hexium_orion. + +source "drivers/media/video/ivtv/Kconfig" config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" @@ -688,8 +740,6 @@ config VIDEO_MEYE To compile this driver as a module, choose M here: the module will be called meye. -source "drivers/media/video/saa7134/Kconfig" - config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_V4L2 && I2C @@ -706,28 +756,119 @@ config VIDEO_MXB To compile this driver as a module, choose M here: the module will be called mxb. -config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV +source "drivers/media/video/saa7134/Kconfig" + +source "drivers/media/video/saa7164/Kconfig" + +source "drivers/media/video/zoran/Kconfig" + +endif # V4L_PCI_DRIVERS + +# +# ISA & parallel port drivers configuration +# + +menuconfig V4L_ISA_PARPORT_DRIVERS + bool "V4L ISA and parallel port devices" + depends on ISA || PARPORT + default n ---help--- - This is a video4linux driver for the Hexium HV-PCI6 and - Orion frame grabber cards by Hexium. + Say Y here to enable support for these ISA and parallel port drivers. + +if V4L_ISA_PARPORT_DRIVERS + +config VIDEO_BWQCAM + tristate "Quickcam BW Video For Linux" + depends on PARPORT && VIDEO_V4L2 + help + Say Y have if you the black and white version of the QuickCam + camera. See the next option for the color version. To compile this driver as a module, choose M here: the - module will be called hexium_orion. + module will be called bw-qcam. -config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - ---help--- - This is a video4linux driver for the Hexium Gemini frame - grabber card by Hexium. Please note that the Gemini Dual - card is *not* fully supported. +config VIDEO_CQCAM + tristate "QuickCam Colour Video For Linux" + depends on PARPORT && VIDEO_V4L2 + help + This is the video4linux driver for the colour version of the + Connectix QuickCam. If you have one of these cameras, say Y here, + otherwise say N. This driver does not work with the original + monochrome QuickCam, QuickCam VC or QuickClip. It is also available + as a module (c-qcam). + Read <file:Documentation/video4linux/CQcam.txt> for more information. + +config VIDEO_PMS + tristate "Mediavision Pro Movie Studio Video For Linux" + depends on ISA && VIDEO_V4L2 + help + Say Y if you have the ISA Mediavision Pro Movie Studio + capture card. To compile this driver as a module, choose M here: the - module will be called hexium_gemini. + module will be called pms. + +config VIDEO_W9966 + tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" + depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 + help + Video4linux driver for Winbond's w9966 based Webcams. + Currently tested with the LifeView FlyCam Supra. + If you have one of these cameras, say Y here + otherwise say N. + This driver is also available as a module (w9966). + + Check out <file:Documentation/video4linux/w9966.txt> for more + information. + +endif # V4L_ISA_PARPORT_DRIVERS + +menuconfig V4L_PLATFORM_DRIVERS + bool "V4L platform devices" + default n + ---help--- + Say Y here to enable support for platform-specific V4L drivers. + +if V4L_PLATFORM_DRIVERS + +source "drivers/media/video/marvell-ccic/Kconfig" + +config VIDEO_VIA_CAMERA + tristate "VIAFB camera controller support" + depends on FB_VIA + select VIDEOBUF_DMA_SG + select VIDEO_OV7670 + help + Driver support for the integrated camera controller in VIA + Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems + with ov7670 sensors. + +# +# Platform multimedia device configuration +# + +source "drivers/media/video/davinci/Kconfig" + +source "drivers/media/video/omap/Kconfig" + +config VIDEO_SH_VOU + tristate "SuperH VOU video output driver" + depends on VIDEO_DEV && ARCH_SHMOBILE + select VIDEOBUF_DMA_CONTIG + help + Support for the Video Output Unit (VOU) on SuperH SoCs. + +config VIDEO_VIU + tristate "Freescale VIU Video Driver" + depends on VIDEO_V4L2 && PPC_MPC512x + select VIDEOBUF_DMA_CONTIG + default y + ---help--- + Support for Freescale VIU video driver. This device captures + video data, or overlays video on DIU frame buffer. + + Say Y here if you want to enable VIU device on MPC5121e Rev2+. + In doubt, say N. config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" @@ -739,21 +880,13 @@ config VIDEO_TIMBERDALE ---help--- Add support for the Video In peripherial of the timberdale FPGA. -source "drivers/media/video/cx88/Kconfig" - -source "drivers/media/video/cx23885/Kconfig" - -source "drivers/media/video/cx25821/Kconfig" - -source "drivers/media/video/au0828/Kconfig" - -source "drivers/media/video/ivtv/Kconfig" - -source "drivers/media/video/cx18/Kconfig" - -source "drivers/media/video/saa7164/Kconfig" - -source "drivers/media/video/marvell-ccic/Kconfig" +config VIDEO_VINO + tristate "SGI Vino Video For Linux" + depends on I2C && SGI_IP22 && VIDEO_V4L2 + select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO + help + Say Y here to build in support for the Vino video input system found + on SGI Indy machines. config VIDEO_M32R_AR tristate "AR devices" @@ -774,16 +907,6 @@ config VIDEO_M32R_AR_M64278 To compile this driver as a module, choose M here: the module will be called arv. -config VIDEO_VIA_CAMERA - tristate "VIAFB camera controller support" - depends on FB_VIA - select VIDEOBUF_DMA_SG - select VIDEO_OV7670 - help - Driver support for the integrated camera controller in VIA - Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems - with ov7670 sensors. - config VIDEO_OMAP3 tristate "OMAP 3 Camera support (EXPERIMENTAL)" depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL @@ -1002,78 +1125,7 @@ config VIDEO_S5P_MIPI_CSIS source "drivers/media/video/s5p-tv/Kconfig" -# -# USB Multimedia device configuration -# - -menuconfig V4L_USB_DRIVERS - bool "V4L USB devices" - depends on USB - default y - -if V4L_USB_DRIVERS && USB - -source "drivers/media/video/uvc/Kconfig" - -source "drivers/media/video/gspca/Kconfig" - -source "drivers/media/video/pvrusb2/Kconfig" - -source "drivers/media/video/hdpvr/Kconfig" - -source "drivers/media/video/em28xx/Kconfig" - -source "drivers/media/video/tlg2300/Kconfig" - -source "drivers/media/video/cx231xx/Kconfig" - -source "drivers/media/video/tm6000/Kconfig" - -source "drivers/media/video/usbvision/Kconfig" - -source "drivers/media/video/et61x251/Kconfig" - -source "drivers/media/video/sn9c102/Kconfig" - -source "drivers/media/video/pwc/Kconfig" - -config USB_ZR364XX - tristate "USB ZR364XX Camera support" - depends on VIDEO_V4L2 - select VIDEOBUF_GEN - select VIDEOBUF_VMALLOC - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. - See <file:Documentation/video4linux/zr364xx.txt> for more info - and list of supported cameras. - - To compile this driver as a module, choose M here: the - module will be called zr364xx. - -config USB_STKWEBCAM - tristate "USB Syntek DC1125 Camera support" - depends on VIDEO_V4L2 && EXPERIMENTAL - ---help--- - Say Y here if you want to use this type of camera. - Supported devices are typically found in some Asus laptops, - with USB id 174f:a311 and 05e1:0501. Other Syntek cameras - may be supported by the stk11xx driver, from which this is - derived, see <http://sourceforge.net/projects/syntekdriver/> - - To compile this driver as a module, choose M here: the - module will be called stkwebcam. - -config USB_S2255 - tristate "USB Sensoray 2255 video capture device" - depends on VIDEO_V4L2 - select VIDEOBUF_VMALLOC - default n - help - Say Y here if you want support for the Sensoray 2255 USB device. - This driver can be compiled as a module, called s2255drv. - -endif # V4L_USB_DRIVERS +endif # V4L_PLATFORM_DRIVERS endif # VIDEO_CAPTURE_DRIVERS menuconfig V4L_MEM2MEM_DRIVERS @@ -1098,6 +1150,23 @@ config VIDEO_MEM2MEM_TESTDEV This is a virtual test device for the memory-to-memory driver framework. +config VIDEO_SAMSUNG_S5P_G2D + tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" + depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + default n + ---help--- + This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D + 2d graphics accelerator. + +config VIDEO_SAMSUNG_S5P_JPEG + tristate "Samsung S5P/Exynos4 JPEG codec driver (EXPERIMENTAL)" + depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P && EXPERIMENTAL + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + ---help--- + This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC 5.1 Video Codec" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 117f9c4b4cb9..354138804cda 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o +obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o @@ -177,9 +178,12 @@ obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ + obj-$(CONFIG_ARCH_DAVINCI) += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c index 23ba5c37c3e4..879f1d839760 100644 --- a/drivers/media/video/adv7170.c +++ b/drivers/media/video/adv7170.c @@ -64,6 +64,11 @@ static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd) static char *inputs[] = { "pass_through", "play_back" }; +static enum v4l2_mbus_pixelcode adv7170_codes[] = { + V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_UYVY8_1X16, +}; + /* ----------------------------------------------------------------------- */ static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value) @@ -258,6 +263,60 @@ static int adv7170_s_routing(struct v4l2_subdev *sd, return 0; } +static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(adv7170_codes)) + return -EINVAL; + + *code = adv7170_codes[index]; + return 0; +} + +static int adv7170_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u8 val = adv7170_read(sd, 0x7); + + if ((val & 0x40) == (1 << 6)) + mf->code = V4L2_MBUS_FMT_UYVY8_1X16; + else + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + + mf->colorspace = V4L2_COLORSPACE_SMPTE170M; + mf->width = 0; + mf->height = 0; + mf->field = V4L2_FIELD_ANY; + + return 0; +} + +static int adv7170_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + u8 val = adv7170_read(sd, 0x7); + int ret; + + switch (mf->code) { + case V4L2_MBUS_FMT_UYVY8_2X8: + val &= ~0x40; + break; + + case V4L2_MBUS_FMT_UYVY8_1X16: + val |= 0x40; + break; + + default: + v4l2_dbg(1, debug, sd, + "illegal v4l2_mbus_framefmt code: %d\n", mf->code); + return -EINVAL; + } + + ret = adv7170_write(sd, 0x7, val); + + return ret; +} + static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -274,6 +333,9 @@ static const struct v4l2_subdev_core_ops adv7170_core_ops = { static const struct v4l2_subdev_video_ops adv7170_video_ops = { .s_std_output = adv7170_s_std_output, .s_routing = adv7170_s_routing, + .s_mbus_fmt = adv7170_s_fmt, + .g_mbus_fmt = adv7170_g_fmt, + .enum_mbus_fmt = adv7170_enum_fmt, }; static const struct v4l2_subdev_ops adv7170_ops = { diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c new file mode 100644 index 000000000000..ec859a580651 --- /dev/null +++ b/drivers/media/video/as3645a.c @@ -0,0 +1,904 @@ +/* + * drivers/media/video/as3645a.c - AS3645A and LM3555 flash controllers driver + * + * Copyright (C) 2008-2011 Nokia Corporation + * Copyright (c) 2011, Intel Corporation. + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * TODO: + * - Check hardware FSTROBE control when sensor driver add support for this + * + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> + +#include <media/as3645a.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> + +#define AS_TIMER_MS_TO_CODE(t) (((t) - 100) / 50) +#define AS_TIMER_CODE_TO_MS(c) (50 * (c) + 100) + +/* Register definitions */ + +/* Read-only Design info register: Reset state: xxxx 0001 */ +#define AS_DESIGN_INFO_REG 0x00 +#define AS_DESIGN_INFO_FACTORY(x) (((x) >> 4)) +#define AS_DESIGN_INFO_MODEL(x) ((x) & 0x0f) + +/* Read-only Version control register: Reset state: 0000 0000 + * for first engineering samples + */ +#define AS_VERSION_CONTROL_REG 0x01 +#define AS_VERSION_CONTROL_RFU(x) (((x) >> 4)) +#define AS_VERSION_CONTROL_VERSION(x) ((x) & 0x0f) + +/* Read / Write (Indicator and timer register): Reset state: 0000 1111 */ +#define AS_INDICATOR_AND_TIMER_REG 0x02 +#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT 0 +#define AS_INDICATOR_AND_TIMER_VREF_SHIFT 4 +#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT 6 + +/* Read / Write (Current set register): Reset state: 0110 1001 */ +#define AS_CURRENT_SET_REG 0x03 +#define AS_CURRENT_ASSIST_LIGHT_SHIFT 0 +#define AS_CURRENT_LED_DET_ON (1 << 3) +#define AS_CURRENT_FLASH_CURRENT_SHIFT 4 + +/* Read / Write (Control register): Reset state: 1011 0100 */ +#define AS_CONTROL_REG 0x04 +#define AS_CONTROL_MODE_SETTING_SHIFT 0 +#define AS_CONTROL_STROBE_ON (1 << 2) +#define AS_CONTROL_OUT_ON (1 << 3) +#define AS_CONTROL_EXT_TORCH_ON (1 << 4) +#define AS_CONTROL_STROBE_TYPE_EDGE (0 << 5) +#define AS_CONTROL_STROBE_TYPE_LEVEL (1 << 5) +#define AS_CONTROL_COIL_PEAK_SHIFT 6 + +/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */ +#define AS_FAULT_INFO_REG 0x05 +#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT (1 << 1) +#define AS_FAULT_INFO_INDICATOR_LED (1 << 2) +#define AS_FAULT_INFO_LED_AMOUNT (1 << 3) +#define AS_FAULT_INFO_TIMEOUT (1 << 4) +#define AS_FAULT_INFO_OVER_TEMPERATURE (1 << 5) +#define AS_FAULT_INFO_SHORT_CIRCUIT (1 << 6) +#define AS_FAULT_INFO_OVER_VOLTAGE (1 << 7) + +/* Boost register */ +#define AS_BOOST_REG 0x0d +#define AS_BOOST_CURRENT_DISABLE (0 << 0) +#define AS_BOOST_CURRENT_ENABLE (1 << 0) + +/* Password register is used to unlock boost register writing */ +#define AS_PASSWORD_REG 0x0f +#define AS_PASSWORD_UNLOCK_VALUE 0x55 + +enum as_mode { + AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT, + AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT, + AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT, + AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT, +}; + +/* + * struct as3645a + * + * @subdev: V4L2 subdev + * @pdata: Flash platform data + * @power_lock: Protects power_count + * @power_count: Power reference count + * @led_mode: V4L2 flash LED mode + * @timeout: Flash timeout in microseconds + * @flash_current: Flash current (0=200mA ... 15=500mA). Maximum + * values are 400mA for two LEDs and 500mA for one LED. + * @assist_current: Torch/Assist light current (0=20mA, 1=40mA ... 7=160mA) + * @indicator_current: Indicator LED current (0=0mA, 1=2.5mA ... 4=10mA) + * @strobe_source: Flash strobe source (software or external) + */ +struct as3645a { + struct v4l2_subdev subdev; + const struct as3645a_platform_data *pdata; + + struct mutex power_lock; + int power_count; + + /* Controls */ + struct v4l2_ctrl_handler ctrls; + + enum v4l2_flash_led_mode led_mode; + unsigned int timeout; + u8 flash_current; + u8 assist_current; + u8 indicator_current; + enum v4l2_flash_strobe_source strobe_source; +}; + +#define to_as3645a(sd) container_of(sd, struct as3645a, subdev) + +/* Return negative errno else zero on success */ +static int as3645a_write(struct as3645a *flash, u8 addr, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + rval = i2c_smbus_write_byte_data(client, addr, val); + + dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, + rval < 0 ? "fail" : "ok"); + + return rval; +} + +/* Return negative errno else a data byte received from the device. */ +static int as3645a_read(struct as3645a *flash, u8 addr) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + rval = i2c_smbus_read_byte_data(client, addr); + + dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval, + rval < 0 ? "fail" : "ok"); + + return rval; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration and trigger + */ + +/* + * as3645a_set_config - Set flash configuration registers + * @flash: The flash + * + * Configure the hardware with flash, assist and indicator currents, as well as + * flash timeout. + * + * Return 0 on success, or a negative error code if an I2C communication error + * occurred. + */ +static int as3645a_set_config(struct as3645a *flash) +{ + int ret; + u8 val; + + val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT) + | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT) + | AS_CURRENT_LED_DET_ON; + + ret = as3645a_write(flash, AS_CURRENT_SET_REG, val); + if (ret < 0) + return ret; + + val = AS_TIMER_MS_TO_CODE(flash->timeout / 1000) + << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT; + + val |= (flash->pdata->vref << AS_INDICATOR_AND_TIMER_VREF_SHIFT) + | ((flash->indicator_current ? flash->indicator_current - 1 : 0) + << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT); + + return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val); +} + +/* + * as3645a_set_control - Set flash control register + * @flash: The flash + * @mode: Desired output mode + * @on: Desired output state + * + * Configure the hardware with output mode and state. + * + * Return 0 on success, or a negative error code if an I2C communication error + * occurred. + */ +static int +as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on) +{ + u8 reg; + + /* Configure output parameters and operation mode. */ + reg = (flash->pdata->peak << AS_CONTROL_COIL_PEAK_SHIFT) + | (on ? AS_CONTROL_OUT_ON : 0) + | mode; + + if (flash->led_mode == V4L2_FLASH_LED_MODE_FLASH && + flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL) { + reg |= AS_CONTROL_STROBE_TYPE_LEVEL + | AS_CONTROL_STROBE_ON; + } + + return as3645a_write(flash, AS_CONTROL_REG, reg); +} + +/* + * as3645a_set_output - Configure output and operation mode + * @flash: Flash controller + * @strobe: Strobe the flash (only valid in flash mode) + * + * Turn the LEDs output on/off and set the operation mode based on the current + * parameters. + * + * The AS3645A can't control the indicator LED independently of the flash/torch + * LED. If the flash controller is in V4L2_FLASH_LED_MODE_NONE mode, set the + * chip to indicator mode. Otherwise set it to assist light (torch) or flash + * mode. + * + * In indicator and assist modes, turn the output on/off based on the indicator + * and torch currents. In software strobe flash mode, turn the output on/off + * based on the strobe parameter. + */ +static int as3645a_set_output(struct as3645a *flash, bool strobe) +{ + enum as_mode mode; + bool on; + + switch (flash->led_mode) { + case V4L2_FLASH_LED_MODE_NONE: + on = flash->indicator_current != 0; + mode = AS_MODE_INDICATOR; + break; + case V4L2_FLASH_LED_MODE_TORCH: + on = true; + mode = AS_MODE_ASSIST; + break; + case V4L2_FLASH_LED_MODE_FLASH: + on = strobe; + mode = AS_MODE_FLASH; + break; + default: + BUG(); + } + + /* Configure output parameters and operation mode. */ + return as3645a_set_control(flash, mode, on); +} + +/* ----------------------------------------------------------------------------- + * V4L2 controls + */ + +static int as3645a_is_active(struct as3645a *flash) +{ + int ret; + + ret = as3645a_read(flash, AS_CONTROL_REG); + return ret < 0 ? ret : !!(ret & AS_CONTROL_OUT_ON); +} + +static int as3645a_read_fault(struct as3645a *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int rval; + + /* NOTE: reading register clear fault status */ + rval = as3645a_read(flash, AS_FAULT_INFO_REG); + if (rval < 0) + return rval; + + if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT) + dev_dbg(&client->dev, "Inductor Peak limit fault\n"); + + if (rval & AS_FAULT_INFO_INDICATOR_LED) + dev_dbg(&client->dev, "Indicator LED fault: " + "Short circuit or open loop\n"); + + dev_dbg(&client->dev, "%u connected LEDs\n", + rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1); + + if (rval & AS_FAULT_INFO_TIMEOUT) + dev_dbg(&client->dev, "Timeout fault\n"); + + if (rval & AS_FAULT_INFO_OVER_TEMPERATURE) + dev_dbg(&client->dev, "Over temperature fault\n"); + + if (rval & AS_FAULT_INFO_SHORT_CIRCUIT) + dev_dbg(&client->dev, "Short circuit fault\n"); + + if (rval & AS_FAULT_INFO_OVER_VOLTAGE) + dev_dbg(&client->dev, "Over voltage fault: " + "Indicates missing capacitor or open connection\n"); + + return rval; +} + +static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct as3645a *flash = + container_of(ctrl->handler, struct as3645a, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int value; + + switch (ctrl->id) { + case V4L2_CID_FLASH_FAULT: + value = as3645a_read_fault(flash); + if (value < 0) + return value; + + ctrl->cur.val = 0; + if (value & AS_FAULT_INFO_SHORT_CIRCUIT) + ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; + if (value & AS_FAULT_INFO_OVER_TEMPERATURE) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; + if (value & AS_FAULT_INFO_TIMEOUT) + ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT; + if (value & AS_FAULT_INFO_OVER_VOLTAGE) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE; + if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT) + ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT; + if (value & AS_FAULT_INFO_INDICATOR_LED) + ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR; + break; + + case V4L2_CID_FLASH_STROBE_STATUS: + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { + ctrl->cur.val = 0; + break; + } + + value = as3645a_is_active(flash); + if (value < 0) + return value; + + ctrl->cur.val = value; + break; + } + + dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val); + + return 0; +} + +static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct as3645a *flash = + container_of(ctrl->handler, struct as3645a, ctrls); + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int ret; + + dev_dbg(&client->dev, "S_CTRL %08x:%d\n", ctrl->id, ctrl->val); + + /* If a control that doesn't apply to the current mode is modified, + * we store the value and return immediately. The setting will be + * applied when the LED mode is changed. Otherwise we apply the setting + * immediately. + */ + + switch (ctrl->id) { + case V4L2_CID_FLASH_LED_MODE: + if (flash->indicator_current) + return -EBUSY; + + ret = as3645a_set_config(flash); + if (ret < 0) + return ret; + + flash->led_mode = ctrl->val; + return as3645a_set_output(flash, false); + + case V4L2_CID_FLASH_STROBE_SOURCE: + flash->strobe_source = ctrl->val; + + /* Applies to flash mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + break; + + return as3645a_set_output(flash, false); + + case V4L2_CID_FLASH_STROBE: + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + return -EBUSY; + + return as3645a_set_output(flash, true); + + case V4L2_CID_FLASH_STROBE_STOP: + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + return -EBUSY; + + return as3645a_set_output(flash, false); + + case V4L2_CID_FLASH_TIMEOUT: + flash->timeout = ctrl->val; + + /* Applies to flash mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + break; + + return as3645a_set_config(flash); + + case V4L2_CID_FLASH_INTENSITY: + flash->flash_current = (ctrl->val - AS3645A_FLASH_INTENSITY_MIN) + / AS3645A_FLASH_INTENSITY_STEP; + + /* Applies to flash mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) + break; + + return as3645a_set_config(flash); + + case V4L2_CID_FLASH_TORCH_INTENSITY: + flash->assist_current = + (ctrl->val - AS3645A_TORCH_INTENSITY_MIN) + / AS3645A_TORCH_INTENSITY_STEP; + + /* Applies to torch mode only. */ + if (flash->led_mode != V4L2_FLASH_LED_MODE_TORCH) + break; + + return as3645a_set_config(flash); + + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + if (flash->led_mode != V4L2_FLASH_LED_MODE_NONE) + return -EBUSY; + + flash->indicator_current = + (ctrl->val - AS3645A_INDICATOR_INTENSITY_MIN) + / AS3645A_INDICATOR_INTENSITY_STEP; + + ret = as3645a_set_config(flash); + if (ret < 0) + return ret; + + if ((ctrl->val == 0) == (ctrl->cur.val == 0)) + break; + + return as3645a_set_output(flash, false); + } + + return 0; +} + +static const struct v4l2_ctrl_ops as3645a_ctrl_ops = { + .g_volatile_ctrl = as3645a_get_ctrl, + .s_ctrl = as3645a_set_ctrl, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +/* Put device into know state. */ +static int as3645a_setup(struct as3645a *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); + int ret; + + /* clear errors */ + ret = as3645a_read(flash, AS_FAULT_INFO_REG); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Fault info: %02x\n", ret); + + ret = as3645a_set_config(flash); + if (ret < 0) + return ret; + + ret = as3645a_set_output(flash, false); + if (ret < 0) + return ret; + + /* read status */ + ret = as3645a_read_fault(flash); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n", + as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG)); + dev_dbg(&client->dev, "AS_CURRENT_SET_REG: %02x\n", + as3645a_read(flash, AS_CURRENT_SET_REG)); + dev_dbg(&client->dev, "AS_CONTROL_REG: %02x\n", + as3645a_read(flash, AS_CONTROL_REG)); + + return ret & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0; +} + +static int __as3645a_set_power(struct as3645a *flash, int on) +{ + int ret; + + if (!on) + as3645a_set_control(flash, AS_MODE_EXT_TORCH, false); + + if (flash->pdata->set_power) { + ret = flash->pdata->set_power(&flash->subdev, on); + if (ret < 0) + return ret; + } + + if (!on) + return 0; + + ret = as3645a_setup(flash); + if (ret < 0) { + if (flash->pdata->set_power) + flash->pdata->set_power(&flash->subdev, 0); + } + + return ret; +} + +static int as3645a_set_power(struct v4l2_subdev *sd, int on) +{ + struct as3645a *flash = to_as3645a(sd); + int ret = 0; + + mutex_lock(&flash->power_lock); + + if (flash->power_count == !on) { + ret = __as3645a_set_power(flash, !!on); + if (ret < 0) + goto done; + } + + flash->power_count += on ? 1 : -1; + WARN_ON(flash->power_count < 0); + +done: + mutex_unlock(&flash->power_lock); + return ret; +} + +static int as3645a_registered(struct v4l2_subdev *sd) +{ + struct as3645a *flash = to_as3645a(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int rval, man, model, rfu, version; + const char *vendor; + + /* Power up the flash driver and read manufacturer ID, model ID, RFU + * and version. + */ + rval = as3645a_set_power(&flash->subdev, 1); + if (rval < 0) + return rval; + + rval = as3645a_read(flash, AS_DESIGN_INFO_REG); + if (rval < 0) + goto power_off; + + man = AS_DESIGN_INFO_FACTORY(rval); + model = AS_DESIGN_INFO_MODEL(rval); + + rval = as3645a_read(flash, AS_VERSION_CONTROL_REG); + if (rval < 0) + goto power_off; + + rfu = AS_VERSION_CONTROL_RFU(rval); + version = AS_VERSION_CONTROL_VERSION(rval); + + /* Verify the chip model and version. */ + if (model != 0x01 || rfu != 0x00) { + dev_err(&client->dev, "AS3645A not detected " + "(model %d rfu %d)\n", model, rfu); + rval = -ENODEV; + goto power_off; + } + + switch (man) { + case 1: + vendor = "AMS, Austria Micro Systems"; + break; + case 2: + vendor = "ADI, Analog Devices Inc."; + break; + case 3: + vendor = "NSC, National Semiconductor"; + break; + case 4: + vendor = "NXP"; + break; + case 5: + vendor = "TI, Texas Instrument"; + break; + default: + vendor = "Unknown"; + } + + dev_info(&client->dev, "Chip vendor: %s (%d) Version: %d\n", vendor, + man, version); + + rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE); + if (rval < 0) + goto power_off; + + rval = as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE); + if (rval < 0) + goto power_off; + + /* Setup default values. This makes sure that the chip is in a known + * state, in case the power rail can't be controlled. + */ + rval = as3645a_setup(flash); + +power_off: + as3645a_set_power(&flash->subdev, 0); + + return rval; +} + +static int as3645a_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return as3645a_set_power(sd, 1); +} + +static int as3645a_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return as3645a_set_power(sd, 0); +} + +static const struct v4l2_subdev_core_ops as3645a_core_ops = { + .s_power = as3645a_set_power, +}; + +static const struct v4l2_subdev_ops as3645a_ops = { + .core = &as3645a_core_ops, +}; + +static const struct v4l2_subdev_internal_ops as3645a_internal_ops = { + .registered = as3645a_registered, + .open = as3645a_open, + .close = as3645a_close, +}; + +/* ----------------------------------------------------------------------------- + * I2C driver + */ +#ifdef CONFIG_PM + +static int as3645a_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct as3645a *flash = to_as3645a(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __as3645a_set_power(flash, 0); + + dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); + + return rval; +} + +static int as3645a_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct as3645a *flash = to_as3645a(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __as3645a_set_power(flash, 1); + + dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); + + return rval; +} + +#else + +#define as3645a_suspend NULL +#define as3645a_resume NULL + +#endif /* CONFIG_PM */ + +/* + * as3645a_init_controls - Create controls + * @flash: The flash + * + * The number of LEDs reported in platform data is used to compute default + * limits. Parameters passed through platform data can override those limits. + */ +static int as3645a_init_controls(struct as3645a *flash) +{ + const struct as3645a_platform_data *pdata = flash->pdata; + struct v4l2_ctrl *ctrl; + int maximum; + + v4l2_ctrl_handler_init(&flash->ctrls, 10); + + /* V4L2_CID_FLASH_LED_MODE */ + v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_LED_MODE, 2, ~7, + V4L2_FLASH_LED_MODE_NONE); + + /* V4L2_CID_FLASH_STROBE_SOURCE */ + v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE_SOURCE, + pdata->ext_strobe ? 1 : 0, + pdata->ext_strobe ? ~3 : ~1, + V4L2_FLASH_STROBE_SOURCE_SOFTWARE); + + flash->strobe_source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; + + /* V4L2_CID_FLASH_STROBE */ + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE, 0, 0, 0, 0); + + /* V4L2_CID_FLASH_STROBE_STOP */ + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0); + + /* V4L2_CID_FLASH_STROBE_STATUS */ + ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_STROBE_STATUS, 0, 1, 1, 1); + if (ctrl != NULL) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + /* V4L2_CID_FLASH_TIMEOUT */ + maximum = pdata->timeout_max; + + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_TIMEOUT, AS3645A_FLASH_TIMEOUT_MIN, + maximum, AS3645A_FLASH_TIMEOUT_STEP, maximum); + + flash->timeout = maximum; + + /* V4L2_CID_FLASH_INTENSITY */ + maximum = pdata->flash_max_current; + + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_INTENSITY, AS3645A_FLASH_INTENSITY_MIN, + maximum, AS3645A_FLASH_INTENSITY_STEP, maximum); + + flash->flash_current = (maximum - AS3645A_FLASH_INTENSITY_MIN) + / AS3645A_FLASH_INTENSITY_STEP; + + /* V4L2_CID_FLASH_TORCH_INTENSITY */ + maximum = pdata->torch_max_current; + + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_TORCH_INTENSITY, + AS3645A_TORCH_INTENSITY_MIN, maximum, + AS3645A_TORCH_INTENSITY_STEP, + AS3645A_TORCH_INTENSITY_MIN); + + flash->assist_current = 0; + + /* V4L2_CID_FLASH_INDICATOR_INTENSITY */ + v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_INDICATOR_INTENSITY, + AS3645A_INDICATOR_INTENSITY_MIN, + AS3645A_INDICATOR_INTENSITY_MAX, + AS3645A_INDICATOR_INTENSITY_STEP, + AS3645A_INDICATOR_INTENSITY_MIN); + + flash->indicator_current = 0; + + /* V4L2_CID_FLASH_FAULT */ + ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, + V4L2_CID_FLASH_FAULT, 0, + V4L2_FLASH_FAULT_OVER_VOLTAGE | + V4L2_FLASH_FAULT_TIMEOUT | + V4L2_FLASH_FAULT_OVER_TEMPERATURE | + V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0); + if (ctrl != NULL) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + flash->subdev.ctrl_handler = &flash->ctrls; + + return flash->ctrls.error; +} + +static int as3645a_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct as3645a *flash; + int ret; + + if (client->dev.platform_data == NULL) + return -ENODEV; + + flash = kzalloc(sizeof(*flash), GFP_KERNEL); + if (flash == NULL) + return -ENOMEM; + + flash->pdata = client->dev.platform_data; + + v4l2_i2c_subdev_init(&flash->subdev, client, &as3645a_ops); + flash->subdev.internal_ops = &as3645a_internal_ops; + flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + ret = as3645a_init_controls(flash); + if (ret < 0) + goto done; + + ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); + if (ret < 0) + goto done; + + flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + + mutex_init(&flash->power_lock); + + flash->led_mode = V4L2_FLASH_LED_MODE_NONE; + +done: + if (ret < 0) { + v4l2_ctrl_handler_free(&flash->ctrls); + kfree(flash); + } + + return ret; +} + +static int __exit as3645a_remove(struct i2c_client *client) +{ + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct as3645a *flash = to_as3645a(subdev); + + v4l2_device_unregister_subdev(subdev); + v4l2_ctrl_handler_free(&flash->ctrls); + media_entity_cleanup(&flash->subdev.entity); + mutex_destroy(&flash->power_lock); + kfree(flash); + + return 0; +} + +static const struct i2c_device_id as3645a_id_table[] = { + { AS3645A_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, as3645a_id_table); + +static const struct dev_pm_ops as3645a_pm_ops = { + .suspend = as3645a_suspend, + .resume = as3645a_resume, +}; + +static struct i2c_driver as3645a_i2c_driver = { + .driver = { + .name = AS3645A_NAME, + .pm = &as3645a_pm_ops, + }, + .probe = as3645a_probe, + .remove = __exit_p(as3645a_remove), + .id_table = as3645a_id_table, +}; + +static int __init as3645a_init(void) +{ + int rval; + + rval = i2c_add_driver(&as3645a_i2c_driver); + if (rval) + pr_err("%s: Failed to register the driver\n", AS3645A_NAME); + + return rval; +} + +static void __exit as3645a_exit(void) +{ + i2c_del_driver(&as3645a_i2c_driver); +} + +module_init(as3645a_init); +module_exit(as3645a_exit); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 8c775c59e120..9fe4519176a4 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c @@ -90,7 +90,10 @@ struct atmel_isi { struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; struct completion complete; + /* ISI peripherial clock */ struct clk *pclk; + /* ISI_MCK, feed to camera sensor to generate pixel clock */ + struct clk *mck; unsigned int irq; struct isi_platform_data *pdata; @@ -766,6 +769,12 @@ static int isi_camera_add_device(struct soc_camera_device *icd) if (ret) return ret; + ret = clk_enable(isi->mck); + if (ret) { + clk_disable(isi->pclk); + return ret; + } + isi->icd = icd; dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n", icd->devnum); @@ -779,6 +788,7 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) BUG_ON(icd != isi->icd); + clk_disable(isi->mck); clk_disable(isi->pclk); isi->icd = NULL; @@ -803,7 +813,7 @@ static int isi_camera_querycap(struct soc_camera_host *ici, return 0; } -static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) +static int isi_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); @@ -874,7 +884,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) if (isi->pdata->has_emb_sync) cfg1 |= ISI_CFG1_EMB_SYNC; - if (isi->pdata->isi_full_mode) + if (isi->pdata->full_mode) cfg1 |= ISI_CFG1_FULL_MODE; isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); @@ -912,6 +922,7 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev) isi->fb_descriptors_phys); iounmap(isi->regs); + clk_put(isi->mck); clk_put(isi->pclk); kfree(isi); @@ -930,7 +941,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) struct isi_platform_data *pdata; pdata = dev->platform_data; - if (!pdata || !pdata->data_width_flags) { + if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { dev_err(&pdev->dev, "No config available for Atmel ISI\n"); return -EINVAL; @@ -959,6 +970,19 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); + /* Get ISI_MCK, provided by programmable clock or external clock */ + isi->mck = clk_get(dev, "isi_mck"); + if (IS_ERR(isi->mck)) { + dev_err(dev, "Failed to get isi_mck\n"); + ret = PTR_ERR(isi->mck); + goto err_clk_get; + } + + /* Set ISI_MCK's frequency, it should be faster than pixel clock */ + ret = clk_set_rate(isi->mck, pdata->mck_hz); + if (ret < 0) + goto err_set_mck_rate; + isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, @@ -1034,9 +1058,12 @@ err_alloc_ctx: isi->p_fb_descriptors, isi->fb_descriptors_phys); err_alloc_descriptors: +err_set_mck_rate: + clk_put(isi->mck); +err_clk_get: kfree(isi); err_alloc_isi: - clk_put(isi->pclk); + clk_put(pclk); return ret; } diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index 0c3a5ba0e857..81ba9d9d1b52 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -2,6 +2,7 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + depends on DVB_CAPTURE_DRIVERS select I2C_ALGOBIT select VIDEO_TVEEPROM select VIDEOBUF_VMALLOC diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c index cbdb65c34f21..05c299fa5d79 100644 --- a/drivers/media/video/au0828/au0828-i2c.c +++ b/drivers/media/video/au0828/au0828-i2c.c @@ -348,7 +348,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int au0828_i2c_register(struct au0828_dev *dev) { dprintk(1, "%s()\n", __func__); diff --git a/drivers/media/video/bt8xx/bt848.h b/drivers/media/video/bt8xx/bt848.h index 0bcd95303bb0..c37e6acffded 100644 --- a/drivers/media/video/bt8xx/bt848.h +++ b/drivers/media/video/bt8xx/bt848.h @@ -30,6 +30,10 @@ #ifndef PCI_DEVICE_ID_BT849 #define PCI_DEVICE_ID_BT849 0x351 #endif +#ifndef PCI_DEVICE_ID_FUSION879 +#define PCI_DEVICE_ID_FUSION879 0x36c +#endif + #ifndef PCI_DEVICE_ID_BT878 #define PCI_DEVICE_ID_BT878 0x36e #endif @@ -37,7 +41,6 @@ #define PCI_DEVICE_ID_BT879 0x36f #endif - /* Brooktree 848 registers */ #define BT848_DSTATUS 0x000 diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 5939021d8eba..ff2933ab705f 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -80,6 +80,8 @@ static void phytec_muxsel(struct bttv *btv, unsigned int input); static void gv800s_muxsel(struct bttv *btv, unsigned int input); static void gv800s_init(struct bttv *btv); +static void td3116_muxsel(struct bttv *btv, unsigned int input); + static int terratec_active_radio_upgrade(struct bttv *btv); static int tea5757_read(struct bttv *btv); static int tea5757_write(struct bttv *btv, int value); @@ -284,7 +286,8 @@ static struct CARD { { 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" }, { 0x217d6606, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, { 0xfff6f6ff, BTTV_BOARD_WINFAST2000, "Leadtek WinFast TV 2000" }, - { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" }, + { 0x03116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 311" }, + { 0x06116000, BTTV_BOARD_SENSORAY311_611, "Sensoray 611" }, { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, @@ -341,6 +344,7 @@ static struct CARD { { 0x15401835, BTTV_BOARD_PV183, "Provideo PV183-6" }, { 0x15401836, BTTV_BOARD_PV183, "Provideo PV183-7" }, { 0x15401837, BTTV_BOARD_PV183, "Provideo PV183-8" }, + { 0x3116f200, BTTV_BOARD_TVT_TD3116, "Tongwei Video Technology TD-3116" }, { 0, -1, NULL } }; @@ -1526,10 +1530,10 @@ struct tvcard bttv_tvcards[] = { GPIO20,22,23: R30,R29,R28 */ }, - [BTTV_BOARD_SENSORAY311] = { + [BTTV_BOARD_SENSORAY311_611] = { /* Clay Kunz <ckunz@mail.arc.nasa.gov> */ - /* you must jumper JP5 for the card to work */ - .name = "Sensoray 311", + /* you must jumper JP5 for the 311 card (PC/104+) to work */ + .name = "Sensoray 311/611", .video_inputs = 5, /* .audio_inputs= 0, */ .svhs = 4, @@ -2879,6 +2883,16 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ABSENT, .tuner_addr = ADDR_UNSET, }, + [BTTV_BOARD_TVT_TD3116] = { + .name = "Tongwei Video Technology TD-3116", + .video_inputs = 16, + .gpiomask = 0xc00ff, + .muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), + .muxsel_hook = td3116_muxsel, + .svhs = NO_SVHS, + .pll = PLL_28, + .tuner_type = TUNER_ABSENT, + }, }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); @@ -3228,6 +3242,42 @@ static void geovision_muxsel(struct bttv *btv, unsigned int input) gpio_bits(0xf, inmux); } +/* + * The TD3116 has 2 74HC4051 muxes wired to the MUX0 input of a bt878. + * The first 74HC4051 has the lower 8 inputs, the second one the higher 8. + * The muxes are controlled via a 74HC373 latch which is connected to + * GPIOs 0-7. GPIO 18 is connected to the LE signal of the latch. + * Q0 of the latch is connected to the Enable (~E) input of the first + * 74HC4051. Q1 - Q3 are connected to S0 - S2 of the same 74HC4051. + * Q4 - Q7 are connected to the second 74HC4051 in the same way. + */ + +static void td3116_latch_value(struct bttv *btv, u32 value) +{ + gpio_bits((1<<18) | 0xff, value); + gpio_bits((1<<18) | 0xff, (1<<18) | value); + udelay(1); + gpio_bits((1<<18) | 0xff, value); +} + +static void td3116_muxsel(struct bttv *btv, unsigned int input) +{ + u32 value; + u32 highbit; + + highbit = (input & 0x8) >> 3 ; + + /* Disable outputs and set value in the mux */ + value = 0x11; /* Disable outputs */ + value |= ((input & 0x7) << 1) << (4 * highbit); + td3116_latch_value(btv, value); + + /* Enable the correct output */ + value &= ~0x11; + value |= ((highbit ^ 0x1) << 4) | highbit; + td3116_latch_value(btv, value); +} + /* ----------------------------------------------------------------------- */ static void bttv_reset_audio(struct bttv *btv) diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 3dd06607aec2..76c301f05095 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -4572,6 +4572,7 @@ static struct pci_device_id bttv_pci_tbl[] = { {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, + {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0}, {0,} }; diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index e3952af7e56e..580c8e682392 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -346,7 +346,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int __devinit init_bttv_i2c(struct bttv *btv) { strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE); diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index c6333595c6b9..c5171619ac79 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -96,7 +96,7 @@ #define BTTV_BOARD_PV_BT878P_PLUS 0x46 #define BTTV_BOARD_FLYVIDEO98EZ 0x47 #define BTTV_BOARD_PV_BT878P_9B 0x48 -#define BTTV_BOARD_SENSORAY311 0x49 +#define BTTV_BOARD_SENSORAY311_611 0x49 #define BTTV_BOARD_RV605 0x4a #define BTTV_BOARD_POWERCLR_MTV878 0x4b #define BTTV_BOARD_WINDVR 0x4c @@ -183,6 +183,7 @@ #define BTTV_BOARD_GEOVISION_GV800S 0x9d #define BTTV_BOARD_GEOVISION_GV800S_SL 0x9e #define BTTV_BOARD_PV183 0x9f +#define BTTV_BOARD_TVT_TD3116 0xa0 /* more card-specific defines */ diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index cd8ff0473184..fda32f52554a 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -72,7 +72,7 @@ struct qcam { static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; -static int force_rgb; +static bool force_rgb; static int video_nr = -1; /* FIXME: parport=auto would never have worked, surely? --RR */ diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 5909f2557ab4..1d64af9adf71 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -31,7 +31,7 @@ MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index d93e5ab45fd3..51c5b9ad67d8 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -35,7 +35,7 @@ MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index c6ff32a6137c..349bd9c2aff5 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -75,7 +75,7 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static unsigned cardtype_c = 1; static unsigned tuner_c = 1; -static unsigned radio_c = 1; +static bool radio_c = 1; static char pal[] = "--"; static char secam[] = "--"; static char ntsc[] = "-"; diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index 040aaa87579d..51609d5c88ce 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -232,7 +232,7 @@ static struct i2c_algo_bit_data cx18_i2c_algo_template = { .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int init_cx18_i2c(struct cx18 *cx) { int i, err; diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h index bdfd1921e300..1180fdc8d983 100644 --- a/drivers/media/video/cx18/cx18-i2c.h +++ b/drivers/media/video/cx18/cx18-i2c.h @@ -24,6 +24,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx); struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw); -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int init_cx18_i2c(struct cx18 *cx); void exit_cx18_i2c(struct cx18 *cx); diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig index ae85a7a7bd73..446f692aabb7 100644 --- a/drivers/media/video/cx231xx/Kconfig +++ b/drivers/media/video/cx231xx/Kconfig @@ -40,10 +40,10 @@ config VIDEO_CX231XX_ALSA config VIDEO_CX231XX_DVB tristate "DVB/ATSC Support for Cx231xx based TV cards" - depends on VIDEO_CX231XX && DVB_CORE + depends on VIDEO_CX231XX && DVB_CORE && DVB_CAPTURE_DRIVERS select VIDEOBUF_DVB - select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE + select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE select DVB_MB86A20S if !DVB_FE_CUSTOMISE ---help--- diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c index 30d13c15739a..a2c2b7d343ec 100644 --- a/drivers/media/video/cx231xx/cx231xx-audio.c +++ b/drivers/media/video/cx231xx/cx231xx-audio.c @@ -111,6 +111,9 @@ static void cx231xx_audio_isocirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->state & DEV_DISCONNECTED) + return; + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -196,6 +199,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; + if (dev->state & DEV_DISCONNECTED) + return; + switch (urb->status) { case 0: /* success */ case -ETIMEDOUT: /* NAK */ @@ -273,6 +279,9 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { @@ -298,7 +307,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; urb->complete = cx231xx_audio_isocirq; @@ -331,6 +340,9 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size; for (i = 0; i < CX231XX_AUDIO_BUFS; i++) { @@ -356,7 +368,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) urb->context = dev; urb->pipe = usb_rcvbulkpipe(dev->udev, dev->adev.end_point_addr); - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->complete = cx231xx_audio_bulkirq; urb->transfer_buffer_length = sb_size; @@ -432,6 +444,11 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } + if (dev->state & DEV_DISCONNECTED) { + cx231xx_errdev("Can't open. the device was removed.\n"); + return -ENODEV; + } + /* Sets volume, mute, etc */ dev->mute = 0; @@ -571,6 +588,9 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream, struct cx231xx *dev = snd_pcm_substream_chip(substream); int retval; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + spin_lock(&dev->adev.slock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 60b021e79864..919ed77b32f2 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -843,25 +843,34 @@ void cx231xx_release_resources(struct cx231xx *dev) cx231xx_remove_from_devlist(dev); + cx231xx_ir_exit(dev); + /* Release I2C buses */ cx231xx_dev_uninit(dev); - cx231xx_ir_exit(dev); + /* delete v4l2 device */ + v4l2_device_unregister(&dev->v4l2_dev); usb_put_dev(dev->udev); /* Mark device as unused */ - cx231xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &cx231xx_devused); + + kfree(dev->video_mode.alt_max_pkt_size); + kfree(dev->vbi_mode.alt_max_pkt_size); + kfree(dev->sliced_cc_mode.alt_max_pkt_size); + kfree(dev->ts1_mode.alt_max_pkt_size); + kfree(dev); + dev = NULL; } /* * cx231xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ -static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev, +static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, int minor) { - struct cx231xx *dev = *devhandle; int retval = -ENOMEM; int errCode; unsigned int maxh, maxw; @@ -1016,7 +1025,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, int i, isoc_pipe = 0; char *speed; char descr[255] = ""; - struct usb_interface *lif = NULL; struct usb_interface_assoc_descriptor *assoc_desc; udev = usb_get_dev(interface_to_usbdev(interface)); @@ -1030,21 +1038,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface, return -ENODEV; /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); - cx231xx_devused |= 1 << nr; - - if (nr >= CX231XX_MAXBOARDS) { - cx231xx_err(DRIVER_NAME - ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } + do { + nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); + if (nr >= CX231XX_MAXBOARDS) { + /* No free device slots */ + cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n", + CX231XX_MAXBOARDS); + return -ENOMEM; + } + } while (test_and_set_bit(nr, &cx231xx_devused)); /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { cx231xx_err(DRIVER_NAME ": out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); return -ENOMEM; } @@ -1071,9 +1079,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* init CIR module TBD */ - /* store the current interface */ - lif = interface; - /*mode_tv: digital=1 or analog=0*/ dev->mode_tv = 0; @@ -1113,9 +1118,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface, le16_to_cpu(udev->descriptor.idProduct), dev->max_iad_interface_count); - /* store the interface 0 back */ - lif = udev->actconfig->interface[0]; - /* increment interface count */ dev->interface_count++; @@ -1126,7 +1128,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (assoc_desc->bFirstInterface != ifnum) { cx231xx_err(DRIVER_NAME ": Not found " "matching IAD interface\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); kfree(dev); dev = NULL; return -ENODEV; @@ -1135,7 +1137,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, cx231xx_info("registering interface %d\n", ifnum); /* save our data pointer in this interface device */ - usb_set_intfdata(lif, dev); + usb_set_intfdata(interface, dev); /* * AV device initialization - only done at the last interface @@ -1145,19 +1147,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface, retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { cx231xx_errdev("v4l2_device_register failed\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); kfree(dev); dev = NULL; return -EIO; } /* allocate device struct */ - retval = cx231xx_init_dev(&dev, udev, nr); + retval = cx231xx_init_dev(dev, udev, nr); if (retval) { - cx231xx_devused &= ~(1 << dev->devno); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; - usb_set_intfdata(lif, NULL); + usb_set_intfdata(interface, NULL); return retval; } @@ -1178,7 +1180,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->video_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1212,7 +1214,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->vbi_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1247,7 +1249,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1283,7 +1285,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, if (dev->ts1_mode.alt_max_pkt_size == NULL) { cx231xx_errdev("out of memory!\n"); - cx231xx_devused &= ~(1 << nr); + clear_bit(dev->devno, &cx231xx_devused); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); dev = NULL; @@ -1334,10 +1336,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) if (!dev->udev) return; - flush_request_modules(dev); + dev->state |= DEV_DISCONNECTED; - /* delete v4l2 device */ - v4l2_device_unregister(&dev->v4l2_dev); + flush_request_modules(dev); /* wait until all current v4l2 io is finished then deallocate resources */ @@ -1351,31 +1352,24 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) "deallocation are deferred on close.\n", video_device_node_name(dev->vdev)); - dev->state |= DEV_MISCONFIGURED; + /* Even having users, it is safe to remove the RC i2c driver */ + cx231xx_ir_exit(dev); + if (dev->USE_ISO) cx231xx_uninit_isoc(dev); else cx231xx_uninit_bulk(dev); - dev->state |= DEV_DISCONNECTED; wake_up_interruptible(&dev->wait_frame); wake_up_interruptible(&dev->wait_stream); } else { - dev->state |= DEV_DISCONNECTED; - cx231xx_release_resources(dev); } cx231xx_close_extension(dev); mutex_unlock(&dev->lock); - if (!dev->users) { - kfree(dev->video_mode.alt_max_pkt_size); - kfree(dev->vbi_mode.alt_max_pkt_size); - kfree(dev->sliced_cc_mode.alt_max_pkt_size); - kfree(dev->ts1_mode.alt_max_pkt_size); - kfree(dev); - dev = NULL; - } + if (!dev->users) + cx231xx_release_resources(dev); } static struct usb_driver cx231xx_usb_driver = { diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index d4457f9488ee..08dd930f882a 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -166,6 +166,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, u8 _i2c_nostop = 0; u8 _i2c_reserve = 0; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + /* Get the I2C period, nostop and reserve parameters */ _i2c_period = i2c_bus->i2c_period; _i2c_nostop = i2c_bus->i2c_nostop; @@ -1071,7 +1074,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, sb_size, cx231xx_isoc_irq_callback, dma_q, 1); urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; k = 0; for (j = 0; j < max_packets; j++) { @@ -1182,7 +1185,7 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->video_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; dev->video_mode.bulk_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c index da9a4a0aab79..7c4e360ba9bc 100644 --- a/drivers/media/video/cx231xx/cx231xx-dvb.c +++ b/drivers/media/video/cx231xx/cx231xx-dvb.c @@ -196,7 +196,7 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -228,7 +228,7 @@ static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c index 45e14cac4622..96176e9db5a2 100644 --- a/drivers/media/video/cx231xx/cx231xx-input.c +++ b/drivers/media/video/cx231xx/cx231xx-input.c @@ -27,12 +27,16 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { + int rc; u8 cmd, scancode; dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__); /* poll IR chip */ - if (1 != i2c_master_recv(ir->c, &cmd, 1)) + rc = i2c_master_recv(ir->c, &cmd, 1); + if (rc < 0) + return rc; + if (rc != 1) return -EIO; /* it seems that 0xFE indicates that a button is still hold @@ -102,11 +106,14 @@ int cx231xx_ir_init(struct cx231xx *dev) ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master; dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n", ir_i2c_bus, info.addr); - i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info); + dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info); return 0; } void cx231xx_ir_exit(struct cx231xx *dev) { + if (dev->ir_i2c_client) + i2c_unregister_device(dev->ir_i2c_client); + dev->ir_i2c_client = NULL; } diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 1c7a4daafecf..8cdee5f78f13 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -93,7 +93,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -452,7 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, return -ENOMEM; } dev->vbi_mode.bulk_ctl.urb[i] = urb; - urb->transfer_flags = 0; + urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; dev->vbi_mode.bulk_ctl.transfer_buffer[i] = kzalloc(sb_size, GFP_KERNEL); diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 6e81f970dc7d..829a41b0c9ef 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -337,7 +337,7 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -440,7 +440,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) if (!dev) return 0; - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + if (dev->state & DEV_DISCONNECTED) return 0; if (urb->status < 0) { @@ -1000,12 +1000,6 @@ static int check_dev(struct cx231xx *dev) cx231xx_errdev("v4l2 ioctl: device not present\n"); return -ENODEV; } - - if (dev->state & DEV_MISCONFIGURED) { - cx231xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } return 0; } @@ -2347,7 +2341,8 @@ static int cx231xx_v4l2_close(struct file *filp) return 0; } - if (dev->users == 1) { + dev->users--; + if (!dev->users) { videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); @@ -2374,7 +2369,6 @@ static int cx231xx_v4l2_close(struct file *filp) cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); } kfree(fh); - dev->users--; wake_up_interruptible_nr(&dev->open, 1); return 0; } diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 2000bc64c497..e17447554a0d 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -377,7 +377,6 @@ struct cx231xx_board { enum cx231xx_dev_state { DEV_INITIALIZED = 0x01, DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, }; enum AFE_MODE { @@ -621,6 +620,7 @@ struct cx231xx { /* For I2C IR support */ struct IR_i2c_init_data init_data; + struct i2c_client *ir_i2c_client; unsigned int stream_on:1; /* Locks streams */ unsigned int vbi_stream_on:1; /* Locks streams for VBI */ diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 67c4a59bd882..f5c79e53e5a1 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -900,6 +900,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) int i, retval = 0; u32 value = 0; u32 gpio_output = 0; + u32 gpio_value; u32 checksum = 0; u32 *dataptr; @@ -907,7 +908,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) /* Save GPIO settings before reset of APU */ retval |= mc417_memory_read(dev, 0x9020, &gpio_output); - retval |= mc417_memory_read(dev, 0x900C, &value); + retval |= mc417_memory_read(dev, 0x900C, &gpio_value); retval = mc417_register_write(dev, IVTV_REG_VPU, 0xFFFFFFED); @@ -991,11 +992,18 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) /* F/W power up disturbs the GPIOs, restore state */ retval |= mc417_register_write(dev, 0x9020, gpio_output); - retval |= mc417_register_write(dev, 0x900C, value); + retval |= mc417_register_write(dev, 0x900C, gpio_value); retval |= mc417_register_read(dev, IVTV_REG_VPU, &value); retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); + /* Hardcoded GPIO's here */ + retval |= mc417_register_write(dev, 0x9020, 0x4000); + retval |= mc417_register_write(dev, 0x900C, 0x4000); + + mc417_register_read(dev, 0x9020, &gpio_output); + mc417_register_read(dev, 0x900C, &gpio_value); + if (retval < 0) printk(KERN_ERR "%s: Error with mc417_register_write\n", __func__); @@ -1015,6 +1023,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); + /* Dynamically change the height based on video standard */ + if (dev->encodernorm.id & V4L2_STD_525_60) + dev->ts1.height = 480; + else + dev->ts1.height = 576; + /* assign frame size */ cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->ts1.height, dev->ts1.width); @@ -1030,7 +1044,7 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); } -static int cx23885_initialize_codec(struct cx23885_dev *dev) +static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) { int version; int retval; @@ -1112,9 +1126,11 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev) mc417_memory_write(dev, 2120, 0x00000080); /* start capturing to the host interface */ - cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); - msleep(10); + if (startencoder) { + cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, + CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE); + msleep(10); + } return 0; } @@ -1196,6 +1212,16 @@ static int cx23885_querymenu(struct cx23885_dev *dev, cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + call_all(dev, core, g_std, id); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_fh *fh = file->private_data; @@ -1208,55 +1234,31 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; dev->encodernorm = cx23885_tvnorms[i]; + + /* Have the drier core notify the subdevices */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, *id); + mutex_unlock(&dev->lock); + return 0; } static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) + struct v4l2_input *i) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_input *input; - int n; - - if (i->index >= 4) - return -EINVAL; - - input = &cx23885_boards[dev->board].input[i->index]; - - if (input->type == 0) - return -EINVAL; - - /* FIXME - * strcpy(i->name, input->name); */ - strcpy(i->name, "unset"); - - if (input->type == CX23885_VMUX_TELEVISION || - input->type == CX23885_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - - for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++) - i->std |= cx23885_tvnorms[n].id; - return 0; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + return cx23885_enum_input(dev, i); } static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - *i = dev->input; - return 0; + return cx23885_get_input(file, priv, i); } static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - if (i >= 4) - return -EINVAL; - - return 0; + return cx23885_set_input(file, priv, i); } static int vidioc_g_tuner(struct file *file, void *priv, @@ -1309,43 +1311,25 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n", - dev->tuner_type); - dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n", - f->tuner, f->type); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (f->tuner != 0) - return -EINVAL; - if (f->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - dev->freq = f->frequency; - - call_all(dev, tuner, s_frequency, f); + return cx23885_set_frequency(file, priv, f); +} - cx23885_initialize_codec(dev); +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - return 0; + return cx23885_get_control(dev, ctl); } static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) + struct v4l2_control *ctl) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - /* Update the A/V core */ - call_all(dev, core, s_ctrl, ctl); - return 0; + return cx23885_set_control(dev, ctl); } static int vidioc_querycap(struct file *file, void *priv, @@ -1636,7 +1620,7 @@ static ssize_t mpeg_read(struct file *file, char __user *data, /* Start mpeg encoder on first read. */ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev) < 0) + if (cx23885_initialize_codec(dev, 1) < 0) return -EINVAL; } } @@ -1677,6 +1661,8 @@ static struct v4l2_file_operations mpeg_fops = { }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { + .vidioc_querystd = vidioc_g_std, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1686,6 +1672,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1746,8 +1733,8 @@ static struct video_device *cx23885_video_dev_alloc( if (NULL == vfd) return NULL; *vfd = *template; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, - type, cx23885_boards[tsport->dev->board].name); + snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", + cx23885_boards[tsport->dev->board].name, type); vfd->parent = &pci->dev; vfd->release = video_device_release; return vfd; @@ -1791,5 +1778,11 @@ int cx23885_417_register(struct cx23885_dev *dev) printk(KERN_INFO "%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->v4l_device)); + /* ST: Configure the encoder paramaters, but don't begin + * encoding, this resolves an issue where the first time the + * encoder is started video can be choppy. + */ + cx23885_initialize_codec(dev, 0); + return 0; } diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index c3cf08945e4c..3c01be999e35 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -335,8 +335,33 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1850] = { .name = "Hauppauge WinTV-HVR1850", + .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_ENCODER, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x42, /* 0x84 >> 1 */ + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1 | + CX25840_DIF_ON, + .amux = CX25840_AUDIO8, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + } }, }, [CX23885_BOARD_COMPRO_VIDEOMATE_E800] = { .name = "Compro VideoMate E800", @@ -438,6 +463,41 @@ struct cx23885_board cx23885_boards[] = { .gpio0 = 0, } }, }, + [CX23885_BOARD_MYGICA_X8507] = { + .name = "Mygica X8507", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x61, + .tuner_bus = 1, + .porta = CX23885_ANALOG_VIDEO, + .input = { + { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE2, + .amux = CX25840_AUDIO8, + }, + { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_COMPOSITE8, + }, + { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_SVIDEO_LUMA3 | + CX25840_SVIDEO_CHROMA4, + }, + { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_COMPONENT_ON | + CX25840_VIN1_CH1 | + CX25840_VIN6_CH2 | + CX25840_VIN7_CH3, + }, + }, + }, + [CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL] = { + .name = "TerraTec Cinergy T PCIe Dual", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + } }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -637,6 +697,14 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x1b55, .subdevice = 0xe2e4, .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8502, + .card = CX23885_BOARD_MYGICA_X8507, + }, { + .subvendor = 0x153b, + .subdevice = 0x117e, + .card = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1068,6 +1136,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_MYGICA_X8506: case CX23885_BOARD_MAGICPRO_PROHDTVE2: + case CX23885_BOARD_MYGICA_X8507: /* GPIO-0 (0)Analog / (1)Digital TV */ /* GPIO-1 reset XC5000 */ /* GPIO-2 reset LGS8GL5 / LGS8G75 */ @@ -1367,6 +1436,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* Defaults for VID B - Analog encoder */ /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */ @@ -1377,6 +1447,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* APB_TSVALERR_POL (active low)*/ ts1->vld_misc_val = 0x2000; ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc); + cx_write(0x130184, 0xc); /* Defaults for VID C */ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ @@ -1396,6 +1467,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) break; case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -1431,7 +1503,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: - case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1290: case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: @@ -1468,6 +1539,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_MPX885: + case CX23885_BOARD_MYGICA_X8507: + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 40e68b22015e..6ad227029a0f 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -206,12 +206,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA1_CNT2, }, [SRAM_CH02] = { - .name = "ch2", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "VID A (VBI)", + .cmds_start = 0x10050, + .ctrl_start = 0x105F0, + .cdt = 0x10810, + .fifo_start = 0x3000, + .fifo_size = 0x1000, .ptr1_reg = DMA2_PTR1, .ptr2_reg = DMA2_PTR2, .cnt1_reg = DMA2_CNT1, @@ -266,12 +266,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA5_CNT2, }, [SRAM_CH07] = { - .name = "ch7", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TV Audio", + .cmds_start = 0x10190, + .ctrl_start = 0x106B0, + .cdt = 0x10930, + .fifo_start = 0x7000, + .fifo_size = 0x1000, .ptr1_reg = DMA6_PTR1, .ptr2_reg = DMA6_PTR2, .cnt1_reg = DMA6_CNT1, diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index bcb45be44bb2..af8a225763d3 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -61,6 +61,8 @@ #include "cx23885-f300.h" #include "altera-ci.h" #include "stv0367.h" +#include "drxk.h" +#include "mt2063.h" static unsigned int debug; @@ -111,6 +113,8 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer *)vb); } +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe); + static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) { struct videobuf_dvb_frontends *f; @@ -125,6 +129,12 @@ static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); + + /* + * FIXME: Improve this path to avoid calling the + * cx23885_dvb_set_frontend() every time it passes here. + */ + cx23885_dvb_set_frontend(fe->dvb.frontend); } static struct videobuf_queue_ops dvb_qops = { @@ -479,15 +489,15 @@ static struct xc5000_config mygica_x8506_xc5000_config = { .if_khz = 5380, }; -static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) +static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1275: - switch (param->u.vsb.modulation) { + switch (p->modulation) { case VSB_8: cx23885_gpio_clear(dev, GPIO_5); break; @@ -507,31 +517,6 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, return 0; } -static int cx23885_dvb_fe_ioctl_override(struct dvb_frontend *fe, - unsigned int cmd, void *parg, - unsigned int stage) -{ - int err = 0; - - switch (stage) { - case DVB_FE_IOCTL_PRE: - - switch (cmd) { - case FE_SET_FRONTEND: - err = cx23885_dvb_set_frontend(fe, - (struct dvb_frontend_parameters *) parg); - break; - } - break; - - case DVB_FE_IOCTL_POST: - /* no post-ioctl handling required */ - break; - } - return err; -}; - - static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { .prod = LGS8GXX_PROD_LGS8G75, .demod_address = 0x19, @@ -617,6 +602,24 @@ static struct xc5000_config netup_xc5000_config[] = { }, }; +static struct drxk_config terratec_drxk_config[] = { + { + .adr = 0x29, + .no_i2c_bridge = 1, + }, { + .adr = 0x2a, + .no_i2c_bridge = 1, + }, +}; + +static struct mt2063_config terratec_mt2063_config[] = { + { + .tuner_address = 0x60, + }, { + .tuner_address = 0x67, + }, +}; + int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -1043,6 +1046,20 @@ static int dvb_register(struct cx23885_tsport *port) } break; case CX23885_BOARD_HAUPPAUGE_HVR1850: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[0].i2c_adap, + &hauppauge_tda18271_config); + + tda18271_attach(&dev->ts1.analog_fe, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + + break; case CX23885_BOARD_HAUPPAUGE_HVR1290: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(s5h1411_attach, @@ -1118,6 +1135,39 @@ static int dvb_register(struct cx23885_tsport *port) goto frontend_detach; } break; + case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + + switch (port->nr) { + /* port b */ + case 1: + fe0->dvb.frontend = dvb_attach(drxk_attach, + &terratec_drxk_config[0], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(mt2063_attach, + fe0->dvb.frontend, + &terratec_mt2063_config[0], + &i2c_bus2->i2c_adap)) + goto frontend_detach; + } + break; + /* port c */ + case 2: + fe0->dvb.frontend = dvb_attach(drxk_attach, + &terratec_drxk_config[1], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(mt2063_attach, + fe0->dvb.frontend, + &terratec_mt2063_config[1], + &i2c_bus2->i2c_adap)) + goto frontend_detach; + } + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -1151,7 +1201,7 @@ static int dvb_register(struct cx23885_tsport *port) /* register everything */ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, mfe_shared, - cx23885_dvb_fe_ioctl_override); + NULL); if (ret) goto frontend_detach; diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 0ff7a9e98f3e..be1e21d8295c 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -309,7 +309,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx23885_i2c_register(struct cx23885_i2c *bus) { struct cx23885_dev *dev = bus->dev; diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index e730b9263016..4bbf9bb97bde 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -253,9 +253,9 @@ static struct cx23885_ctrl cx23885_ctls[] = { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, + .maximum = 65535, + .step = 65535 / 100, + .default_value = 65535, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = PATH1_VOL_CTL, @@ -316,7 +316,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, __func__, bc); } -static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) { dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, @@ -344,8 +344,8 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, cx23885_boards[dev->board].name); + snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", + cx23885_boards[dev->board].name, type); video_set_drvdata(vfd, dev); return vfd; } @@ -492,7 +492,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) dev->input = input; if (dev->board == CX23885_BOARD_MYGICA_X8506 || - dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2) { + dev->board == CX23885_BOARD_MAGICPRO_PROHDTVE2 || + dev->board == CX23885_BOARD_MYGICA_X8507) { /* Select Analog TV */ if (INPUT(input)->type == CX23885_VMUX_TELEVISION) cx23885_gpio_clear(dev, GPIO_0); @@ -503,7 +504,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) INPUT(input)->vmux, 0, 0); if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) || - (dev->board == CX23885_BOARD_MPX885)) { + (dev->board == CX23885_BOARD_MPX885) || + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); @@ -649,6 +651,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, int rc, init_buffer = 0; u32 line0_offset, line1_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + int field_tff; BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || @@ -690,15 +693,25 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->bpl, 0, buf->vb.height); break; case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) { + if (dev->tvnorm & V4L2_STD_NTSC) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; + + if (field_tff) { /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating NTSC risc\n", + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); line0_offset = buf->bpl; line1_offset = 0; } else { /* All other formats are top field first */ - dprintk(1, "%s() Creating PAL/SECAM risc\n", + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); line0_offset = 0; line1_offset = buf->bpl; @@ -981,6 +994,8 @@ static int video_release(struct file *file) } videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&fh->vbiq); + file->private_data = NULL; kfree(fh); @@ -1002,7 +1017,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -static int cx23885_get_control(struct cx23885_dev *dev, +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); @@ -1010,7 +1025,7 @@ static int cx23885_get_control(struct cx23885_dev *dev, return 0; } -static int cx23885_set_control(struct cx23885_dev *dev, +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); @@ -1229,6 +1244,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __func__); + + call_all(dev, core, g_std, id); + + return 0; +} + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1241,7 +1266,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) return 0; } -static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) { static const char *iname[] = { [CX23885_VMUX_COMPOSITE1] = "Composite1", @@ -1278,6 +1303,15 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) if (INPUT(n)->type != CX23885_VMUX_TELEVISION) i->audioset = 0x3; + if (dev->input == n) { + /* enum'd input matches our configured input. + * Ask the video decoder to process the call + * and give it an oppertunity to update the + * status field. + */ + call_all(dev, video, g_input_status, &i->status); + } + return 0; } @@ -1289,7 +1323,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return cx23885_enum_input(dev, i); } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +int cx23885_get_input(struct file *file, void *priv, unsigned int *i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1298,7 +1332,12 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + return cx23885_get_input(file, priv, i); +} + +int cx23885_set_input(struct file *file, void *priv, unsigned int i) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; @@ -1322,6 +1361,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return cx23885_set_input(file, priv, i); +} + static int vidioc_log_status(struct file *file, void *priv) { struct cx23885_fh *fh = priv; @@ -1329,11 +1373,11 @@ static int vidioc_log_status(struct file *file, void *priv) printk(KERN_INFO "%s/0: ============ START LOG STATUS ============\n", - dev->name); + dev->name); call_all(dev, core, log_status); printk(KERN_INFO "%s/0: ============= END LOG STATUS =============\n", - dev->name); + dev->name); return 0; } @@ -1471,6 +1515,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) { + struct v4l2_control ctrl; + if (unlikely(UNSET == dev->tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) @@ -1479,29 +1525,102 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) mutex_lock(&dev->lock); dev->freq = f->frequency; + /* I need to mute audio here */ + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + cx23885_set_control(dev, &ctrl); + call_all(dev, tuner, s_frequency, f); /* When changing channels it is required to reset TVAUDIO */ - msleep(10); + msleep(100); + + /* I need to unmute audio here */ + ctrl.value = 0; + cx23885_set_control(dev, &ctrl); mutex_unlock(&dev->lock); return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) +static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, + struct v4l2_frequency *f) +{ + struct v4l2_control ctrl; + struct videobuf_dvb_frontend *vfe; + struct dvb_frontend *fe; + int err = 0; + + struct analog_parameters params = { + .mode = V4L2_TUNER_ANALOG_TV, + .audmode = V4L2_TUNER_MODE_STEREO, + .std = dev->tvnorm, + .frequency = f->frequency + }; + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + /* I need to mute audio here */ + ctrl.id = V4L2_CID_AUDIO_MUTE; + ctrl.value = 1; + cx23885_set_control(dev, &ctrl); + + /* If HVR1850 */ + dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, + params.frequency, f->tuner, params.std); + + vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + if (!vfe) + err = -EINVAL; + + fe = vfe->dvb.frontend; + + if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) + fe = &dev->ts1.analog_fe; + + if (fe && fe->ops.tuner_ops.set_analog_params) { + call_all(dev, core, s_std, dev->tvnorm); + fe->ops.tuner_ops.set_analog_params(fe, ¶ms); + } + else + printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(100); + + /* I need to unmute audio here */ + ctrl.value = 0; + cx23885_set_control(dev, &ctrl); + + mutex_unlock(&dev->lock); + + return 0; +} + +int cx23885_set_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; + int ret; - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; + switch (dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1850: + ret = cx23885_set_freq_via_ops(dev, f); + break; + default: + ret = cx23885_set_freq(dev, f); + } - return - cx23885_set_freq(dev, f); + return ret; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + return cx23885_set_frequency(file, priv, f); } /* ----------------------------------------------------------- */ @@ -1613,6 +1732,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, + .vidioc_querystd = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index b49036fe3ffd..f020f0568df4 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -87,6 +87,8 @@ #define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000 31 #define CX23885_BOARD_MPX885 32 +#define CX23885_BOARD_MYGICA_X8507 33 +#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -226,6 +228,8 @@ struct cx23885_board { u32 clk_freq; struct cx23885_input input[MAX_CX23885_INPUT]; int ci_type; /* for NetUP */ + /* Force bottom field first during DMA (888 workaround) */ + u32 force_bff; }; struct cx23885_subid { @@ -310,6 +314,9 @@ struct cx23885_tsport { u32 num_frontends; void (*gate_ctrl)(struct cx23885_tsport *port, int open); void *port_priv; + + /* Workaround for a temp dvb_frontend that the tuner can attached to */ + struct dvb_frontend analog_fe; }; struct cx23885_kernel_ir { @@ -574,6 +581,13 @@ extern void cx23885_video_unregister(struct cx23885_dev *dev); extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); extern void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count); +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); +int cx23885_set_input(struct file *file, void *priv, unsigned int i); +int cx23885_get_input(struct file *file, void *priv, unsigned int *i); +int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f); +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); /* ----------------------------------------------------------- */ /* cx23885-vbi.c */ diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c index 09e99de5fd21..03cfac476b03 100644 --- a/drivers/media/video/cx25821/cx25821-alsa.c +++ b/drivers/media/video/cx25821/cx25821-alsa.c @@ -102,7 +102,7 @@ struct cx25821_audio_dev { static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; +static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled."); @@ -176,8 +176,7 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) /* Set the input mode to 16-bit */ tmp = cx_read(AUD_A_CFG); - cx_write(AUD_A_CFG, - tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | + cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | FLD_AUD_CLK_ENABLE); /* @@ -188,9 +187,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) */ /* Enables corresponding bits at AUD_INT_STAT */ - cx_write(AUD_A_INT_MSK, - FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | FLD_AUD_DST_SYNC | - FLD_AUD_DST_OPC_ERR); + cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | + FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR); /* Clean any pending interrupt bits already set */ cx_write(AUD_A_INT_STAT, ~0); @@ -200,8 +198,8 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) /* Turn on audio downstream fifo and risc enable 0x101 */ tmp = cx_read(AUD_INT_DMA_CTL); - cx_set(AUD_INT_DMA_CTL, - tmp | (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); + cx_set(AUD_INT_DMA_CTL, tmp | + (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); mdelay(100); return 0; @@ -220,9 +218,8 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) /* disable irqs */ cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); - cx_clear(AUD_A_INT_MSK, - AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | AUD_INT_DN_RISCI2 | - AUD_INT_DN_RISCI1); + cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | + AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); return 0; } @@ -234,15 +231,15 @@ static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) */ static char *cx25821_aud_irqs[32] = { "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ - NULL, /* reserved */ + NULL, /* reserved */ "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ - NULL, /* reserved */ - "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ - NULL, /* reserved */ - "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ - NULL, /* reserved */ - "opc_err", "par_err", "rip_err", /* 16-18 */ - "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ + NULL, /* reserved */ + "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ + NULL, /* reserved */ + "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ + NULL, /* reserved */ + "opc_err", "par_err", "rip_err", /* 16-18 */ + "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ }; /* @@ -258,10 +255,8 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, cx_write(AUD_A_INT_STAT, status); if (debug > 1 || (status & mask & ~0xff)) - cx25821_print_irqbits(dev->name, "irq aud", - cx25821_aud_irqs, - ARRAY_SIZE(cx25821_aud_irqs), status, - mask); + cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs, + ARRAY_SIZE(cx25821_aud_irqs), status, mask); /* risc op code error */ if (status & AUD_INT_OPC_ERR) { @@ -270,8 +265,7 @@ static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, cx_clear(AUD_INT_DMA_CTL, FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); cx25821_sram_channel_dump_audio(dev, - &cx25821_sram_channels - [AUDIO_SRAM_CHANNEL]); + &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]); } if (status & AUD_INT_DN_SYNC) { pr_warn("WARNING %s: Downstream sync error!\n", dev->name); @@ -317,8 +311,9 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id) cx25821_aud_irq(chip, audint_status, audint_mask); break; - } else + } else { goto out; + } } handled = 1; @@ -361,9 +356,8 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip) */ #define DEFAULT_FIFO_SIZE 384 static struct snd_pcm_hardware snd_cx25821_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_48000, @@ -396,8 +390,8 @@ static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream) return -ENODEV; } - err = - snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; @@ -468,8 +462,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, dma = &buf->dma; videobuf_dma_init(dma); ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, - (PAGE_ALIGN(chip->dma_size) >> - PAGE_SHIFT)); + (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; @@ -477,10 +470,8 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto error; - ret = - cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, - chip->period_size, chip->num_periods, - 1); + ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, + chip->period_size, chip->num_periods, 1); if (ret < 0) { pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); goto error; @@ -686,7 +677,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) } err = snd_card_create(index[devno], id[devno], THIS_MODULE, - sizeof(struct cx25821_audio_dev), &card); + sizeof(struct cx25821_audio_dev), &card); if (err < 0) { pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n", __func__); @@ -711,8 +702,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) IRQF_SHARED, chip->dev->name, chip); if (err < 0) { - pr_err("ERROR %s: can't get IRQ %d for ALSA\n", - chip->dev->name, dev->pci->irq); + pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name, + dev->pci->irq); goto error; } @@ -730,8 +721,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) chip->iobase, chip->irq); strcpy(card->mixername, "CX25821"); - pr_info("%s/%i: ALSA support for cx25821 boards\n", - card->driver, devno); + pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver, + devno); err = snd_card_register(card); if (err < 0) { diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c index c20d6dece154..20c7ca3351a8 100644 --- a/drivers/media/video/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c @@ -107,7 +107,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, { unsigned int line; struct sram_channel *sram_ch = - dev->channels[dev->_audio_upstream_channel].sram_channels; + dev->channels[dev->_audio_upstream_channel].sram_channels; int offset = 0; /* scan lines */ @@ -175,10 +175,8 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, } rp = cx25821_risc_field_upstream_audio(dev, rp, - dev-> - _audiodata_buf_phys_addr - + databuf_offset, bpl, - fifo_enable); + dev->_audiodata_buf_phys_addr + databuf_offset, + bpl, fifo_enable); if (USE_RISC_NOOP_AUDIO) { for (i = 0; i < NUM_NO_OPS; i++) @@ -193,7 +191,7 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, /* Recalculate virtual address based on frame index */ rp = dev->_risc_virt_addr + RISC_SYNC_INSTRUCTION_SIZE / 4 + - (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); + (AUDIO_RISC_DMA_BUF_SIZE * (frame + 1) / 4); } return 0; @@ -218,7 +216,7 @@ void cx25821_free_memory_audio(struct cx25821_dev *dev) void cx25821_stop_upstream_audio(struct cx25821_dev *dev) { struct sram_channel *sram_ch = - dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; + dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; u32 tmp = 0; if (!dev->_audio_is_running) { @@ -286,14 +284,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, } else { if (!(myfile->f_op)) { pr_err("%s(): File has no file operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } if (!myfile->f_op->read) { pr_err("%s(): File has no READ operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } @@ -305,14 +303,14 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, for (i = 0; i < dev->_audio_lines_count; i++) { pos = file_offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size && dev->_audiodata_buf_virt_addr != NULL) { memcpy((void *)(dev->_audiodata_buf_virt_addr + frame_offset / 4), mybuf, - vfs_read_retval); + vfs_read_retval); } file_offset += vfs_read_retval; @@ -328,8 +326,8 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, if (i > 0) dev->_audioframe_count++; - dev->_audiofile_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_audiofile_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); filp_close(myfile, NULL); @@ -340,12 +338,12 @@ int cx25821_get_audio_data(struct cx25821_dev *dev, static void cx25821_audioups_handler(struct work_struct *work) { - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _audio_work_entry); + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _audio_work_entry); if (!dev) { pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); + __func__); return; } @@ -370,19 +368,19 @@ int cx25821_openfile_audio(struct cx25821_dev *dev, if (IS_ERR(myfile)) { const int open_errno = -PTR_ERR(myfile); pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_audiofilename, open_errno); + __func__, dev->_audiofilename, open_errno); return PTR_ERR(myfile); } else { if (!(myfile->f_op)) { pr_err("%s(): File has no file operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } if (!myfile->f_op->read) { pr_err("%s(): File has no READ operations registered!\n", - __func__); + __func__); filp_close(myfile, NULL); return -EIO; } @@ -395,12 +393,12 @@ int cx25821_openfile_audio(struct cx25821_dev *dev, for (i = 0; i < dev->_audio_lines_count; i++) { pos = offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_audiodata_buf_virt_addr != NULL) { + if (vfs_read_retval > 0 && + vfs_read_retval == line_size && + dev->_audiodata_buf_virt_addr != NULL) { memcpy((void *)(dev-> _audiodata_buf_virt_addr + offset / 4), mybuf, @@ -423,8 +421,8 @@ int cx25821_openfile_audio(struct cx25821_dev *dev, break; } - dev->_audiofile_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_audiofile_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); myfile->f_pos = 0; @@ -444,9 +442,8 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, cx25821_free_memory_audio(dev); - dev->_risc_virt_addr = - pci_alloc_consistent(dev->pci, dev->audio_upstream_riscbuf_size, - &dma_addr); + dev->_risc_virt_addr = pci_alloc_consistent(dev->pci, + dev->audio_upstream_riscbuf_size, &dma_addr); dev->_risc_virt_start_addr = dev->_risc_virt_addr; dev->_risc_phys_start_addr = dma_addr; dev->_risc_phys_addr = dma_addr; @@ -454,22 +451,21 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, if (!dev->_risc_virt_addr) { printk(KERN_DEBUG - pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); + pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for RISC program! Returning\n")); return -ENOMEM; } /* Clear out memory at address */ memset(dev->_risc_virt_addr, 0, dev->_audiorisc_size); /* For Audio Data buffer allocation */ - dev->_audiodata_buf_virt_addr = - pci_alloc_consistent(dev->pci, dev->audio_upstream_databuf_size, - &data_dma_addr); + dev->_audiodata_buf_virt_addr = pci_alloc_consistent(dev->pci, + dev->audio_upstream_databuf_size, &data_dma_addr); dev->_audiodata_buf_phys_addr = data_dma_addr; dev->_audiodata_buf_size = dev->audio_upstream_databuf_size; if (!dev->_audiodata_buf_virt_addr) { printk(KERN_DEBUG - pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); + pr_fmt("ERROR: pci_alloc_consistent() FAILED to allocate memory for data buffer! Returning\n")); return -ENOMEM; } /* Clear out memory at address */ @@ -480,12 +476,11 @@ static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, return ret; /* Creating RISC programs */ - ret = - cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, - dev->_audio_lines_count); + ret = cx25821_risc_buffer_upstream_audio(dev, dev->pci, bpl, + dev->_audio_lines_count); if (ret < 0) { printk(KERN_DEBUG - pr_fmt("ERROR creating audio upstream RISC programs!\n")); + pr_fmt("ERROR creating audio upstream RISC programs!\n")); goto error; } @@ -533,9 +528,9 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, if (dev->_risc_virt_start_addr != NULL) { risc_phys_jump_addr = - dev->_risc_phys_start_addr + - RISC_SYNC_INSTRUCTION_SIZE + - AUDIO_RISC_DMA_BUF_SIZE; + dev->_risc_phys_start_addr + + RISC_SYNC_INSTRUCTION_SIZE + + AUDIO_RISC_DMA_BUF_SIZE; rp = cx25821_risc_field_upstream_audio(dev, dev->_risc_virt_start_addr + 1, @@ -632,7 +627,7 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, /* 10 millisecond timeout */ if (count++ > 1000) { pr_err("ERROR: %s() fifo is NOT turned on. Timeout!\n", - __func__); + __func__); return; } @@ -661,9 +656,9 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, /* Set the input mode to 16-bit */ tmp = cx_read(sram_ch->aud_cfg); - tmp |= - FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | - FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | FLD_AUD_SONY_MODE; + tmp |= FLD_AUD_SRC_ENABLE | FLD_AUD_DST_PK_MODE | FLD_AUD_CLK_ENABLE | + FLD_AUD_MASTER_MODE | FLD_AUD_CLK_SELECT_PLL_D | + FLD_AUD_SONY_MODE; cx_write(sram_ch->aud_cfg, tmp); /* Read and write back the interrupt status register to clear it */ @@ -678,12 +673,11 @@ int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp |= _intr_msk); - err = - request_irq(dev->pci->irq, cx25821_upstream_irq_audio, + err = request_irq(dev->pci->irq, cx25821_upstream_irq_audio, IRQF_SHARED, dev->name, dev); if (err < 0) { - pr_err("%s: can't get upstream IRQ %d\n", - dev->name, dev->pci->irq); + pr_err("%s: can't get upstream IRQ %d\n", dev->name, + dev->pci->irq); goto fail_irq; } @@ -726,7 +720,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) if (!dev->_irq_audio_queues) { printk(KERN_DEBUG - pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); + pr_fmt("ERROR: create_singlethread_workqueue() for Audio FAILED!\n")); return -ENOMEM; } @@ -739,33 +733,30 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) if (dev->input_audiofilename) { str_length = strlen(dev->input_audiofilename); - dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_audiofilename = kmemdup(dev->input_audiofilename, + str_length + 1, GFP_KERNEL); if (!dev->_audiofilename) goto error; - memcpy(dev->_audiofilename, dev->input_audiofilename, - str_length + 1); - /* Default if filename is empty string */ if (strcmp(dev->input_audiofilename, "") == 0) dev->_audiofilename = "/root/audioGOOD.wav"; } else { str_length = strlen(_defaultAudioName); - dev->_audiofilename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_audiofilename = kmemdup(_defaultAudioName, + str_length + 1, GFP_KERNEL); if (!dev->_audiofilename) goto error; - - memcpy(dev->_audiofilename, _defaultAudioName, str_length + 1); } retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, _line_size, 0); dev->audio_upstream_riscbuf_size = - AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + - RISC_SYNC_INSTRUCTION_SIZE; + AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + + RISC_SYNC_INSTRUCTION_SIZE; dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS; /* Allocating buffers and prepare RISC program */ @@ -773,7 +764,7 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) _line_size); if (retval < 0) { pr_err("%s: Failed to set up Audio upstream buffers!\n", - dev->name); + dev->name); goto error; } /* Start RISC engine */ diff --git a/drivers/media/video/cx25821/cx25821-audio.h b/drivers/media/video/cx25821/cx25821-audio.h index 8eb55b7b88cb..1fc2d24f5110 100644 --- a/drivers/media/video/cx25821/cx25821-audio.h +++ b/drivers/media/video/cx25821/cx25821-audio.h @@ -23,39 +23,40 @@ #ifndef __CX25821_AUDIO_H__ #define __CX25821_AUDIO_H__ -#define USE_RISC_NOOP 1 -#define LINES_PER_BUFFER 15 -#define AUDIO_LINE_SIZE 128 +#define USE_RISC_NOOP 1 +#define LINES_PER_BUFFER 15 +#define AUDIO_LINE_SIZE 128 /* Number of buffer programs to use at once. */ -#define NUMBER_OF_PROGRAMS 8 +#define NUMBER_OF_PROGRAMS 8 /* * Max size of the RISC program for a buffer. - worst case is 2 writes per line * Space is also added for the 4 no-op instructions added on the end. */ #ifndef USE_RISC_NOOP -#define MAX_BUFFER_PROGRAM_SIZE \ - (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE * 4) +#define MAX_BUFFER_PROGRAM_SIZE \ + (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ + RISC_WRITECR_INSTRUCTION_SIZE * 4) #endif /* MAE 12 July 2005 Try to use NOOP RISC instruction instead */ #ifdef USE_RISC_NOOP -#define MAX_BUFFER_PROGRAM_SIZE \ - (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ - RISC_NOOP_INSTRUCTION_SIZE * 4) +#define MAX_BUFFER_PROGRAM_SIZE \ + (2 * LINES_PER_BUFFER * RISC_WRITE_INSTRUCTION_SIZE + \ + RISC_NOOP_INSTRUCTION_SIZE * 4) #endif /* Sizes of various instructions in bytes. Used when adding instructions. */ -#define RISC_WRITE_INSTRUCTION_SIZE 12 -#define RISC_JUMP_INSTRUCTION_SIZE 12 -#define RISC_SKIP_INSTRUCTION_SIZE 4 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_NOOP_INSTRUCTION_SIZE 4 - -#define MAX_AUDIO_DMA_BUFFER_SIZE \ -(MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + RISC_SYNC_INSTRUCTION_SIZE) +#define RISC_WRITE_INSTRUCTION_SIZE 12 +#define RISC_JUMP_INSTRUCTION_SIZE 12 +#define RISC_SKIP_INSTRUCTION_SIZE 4 +#define RISC_SYNC_INSTRUCTION_SIZE 4 +#define RISC_WRITECR_INSTRUCTION_SIZE 16 +#define RISC_NOOP_INSTRUCTION_SIZE 4 + +#define MAX_AUDIO_DMA_BUFFER_SIZE \ + (MAX_BUFFER_PROGRAM_SIZE * NUMBER_OF_PROGRAMS + \ + RISC_SYNC_INSTRUCTION_SIZE) #endif diff --git a/drivers/media/video/cx25821/cx25821-cards.c b/drivers/media/video/cx25821/cx25821-cards.c index 6ace60313b49..99988c988095 100644 --- a/drivers/media/video/cx25821/cx25821-cards.c +++ b/drivers/media/video/cx25821/cx25821-cards.c @@ -67,6 +67,6 @@ void cx25821_card_setup(struct cx25821_dev *dev) if (dev->i2c_bus[0].i2c_rc == 0) { dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, - sizeof(eeprom)); + sizeof(eeprom)); } } diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index a7fa38f9594e..f617474f9073 100644 --- a/drivers/media/video/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c @@ -804,8 +804,8 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, u32 format) { if (channel_select <= 7 && channel_select >= 0) { - cx_write(dev->channels[channel_select]. - sram_channels->pix_frmt, format); + cx_write(dev->channels[channel_select].sram_channels->pix_frmt, + format); dev->channels[channel_select].pixel_formats = format; } } @@ -855,21 +855,19 @@ static void cx25821_initialize(struct cx25821_dev *dev) } cx25821_sram_channel_setup_audio(dev, - dev->channels[SRAM_CH08].sram_channels, - 128, 0); + dev->channels[SRAM_CH08].sram_channels, 128, 0); cx25821_gpio_init(dev); } static int cx25821_get_resources(struct cx25821_dev *dev) { - if (request_mem_region - (pci_resource_start(dev->pci, 0), pci_resource_len(dev->pci, 0), - dev->name)) + if (request_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0), dev->name)) return 0; pr_err("%s: can't get MMIO memory @ 0x%llx\n", - dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); + dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); return -EBUSY; } @@ -972,8 +970,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->lmmio = ioremap(dev->base_io_addr, pci_resource_len(dev->pci, 0)); if (!dev->lmmio) { - CX25821_ERR - ("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); + CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n"); cx25821_iounmap(dev); return -ENOMEM; } @@ -994,7 +991,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) * cx25821_i2c_register(&dev->i2c_bus[2]); */ CX25821_INFO("i2c register! bus->i2c_rc = %d\n", - dev->i2c_bus[0].i2c_rc); + dev->i2c_bus[0].i2c_rc); cx25821_card_setup(dev); @@ -1004,9 +1001,8 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) cx25821_video_register(dev); /* register IOCTL device */ - dev->ioctl_dev = - cx25821_vdev_init(dev, dev->pci, &cx25821_videoioctl_template, - "video"); + dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_videoioctl_template, "video"); if (video_register_device (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) { @@ -1103,16 +1099,15 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, } if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ - *(rp++) = - cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | RISC_EOL | + bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++) = - cpu_to_le32(RISC_WRITE | RISC_SOL | + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_SOL | (sg_dma_len(sg) - offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ @@ -1120,8 +1115,8 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist, offset = 0; sg++; while (todo > sg_dma_len(sg)) { - *(rp++) = - cpu_to_le32(RISC_WRITE | sg_dma_len(sg)); + *(rp++) = cpu_to_le32(RISC_WRITE | + sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); @@ -1160,8 +1155,8 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, can cause next bpl to start close to a page border. First DMA region may be smaller than PAGE_SIZE */ /* write and jump need and extra dword */ - instructions = - fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + + lines); instructions += 2; rc = btcx_riscmem_alloc(pci, risc, instructions * 12); @@ -1215,8 +1210,8 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ - *(rp++) = - cpu_to_le32(RISC_WRITE | sol | RISC_EOL | bpl); + *(rp++) = cpu_to_le32(RISC_WRITE | sol | RISC_EOL | + bpl); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ offset += bpl; @@ -1224,7 +1219,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, /* scanline needs to be split */ todo = bpl; *(rp++) = cpu_to_le32(RISC_WRITE | sol | - (sg_dma_len(sg) - offset)); + (sg_dma_len(sg) - offset)); *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= (sg_dma_len(sg) - offset); @@ -1232,7 +1227,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist, sg++; while (todo > sg_dma_len(sg)) { *(rp++) = cpu_to_le32(RISC_WRITE | - sg_dma_len(sg)); + sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ todo -= sg_dma_len(sg); @@ -1339,8 +1334,8 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id) sram_channels->int_stat); if (vid_status) - handled += - cx25821_video_irq(dev, i, vid_status); + handled += cx25821_video_irq(dev, i, + vid_status); cx_write(PCI_INT_STAT, mask[i]); } @@ -1427,9 +1422,8 @@ static int __devinit cx25821_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = - request_irq(pci_dev->irq, cx25821_irq, IRQF_SHARED, - dev->name, dev); + err = request_irq(pci_dev->irq, cx25821_irq, + IRQF_SHARED, dev->name, dev); if (err < 0) { pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); @@ -1512,6 +1506,5 @@ static void __exit cx25821_fini(void) pci_unregister_driver(&cx25821_pci_driver); } - module_init(cx25821_init); module_exit(cx25821_fini); diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c index 4d3d0ce40785..12d7300fa1e9 100644 --- a/drivers/media/video/cx25821/cx25821-i2c.c +++ b/drivers/media/video/cx25821/cx25821-i2c.c @@ -252,8 +252,8 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && msgs[i].addr == msgs[i + 1].addr) { /* write then read from same address */ - retval = - i2c_sendbytes(i2c_adap, &msgs[i], msgs[i + 1].len); + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); if (retval < 0) goto err; @@ -276,10 +276,8 @@ err: static u32 cx25821_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_I2C | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA; } static struct i2c_algorithm cx25821_i2c_algo_template = { @@ -300,7 +298,7 @@ static struct i2c_client cx25821_i2c_client_template = { .name = "cx25821 internal", }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx25821_i2c_register(struct cx25821_i2c *bus) { struct cx25821_dev *dev = bus->dev; diff --git a/drivers/media/video/cx25821/cx25821-medusa-defines.h b/drivers/media/video/cx25821/cx25821-medusa-defines.h index 60d197f57556..7a9e6470ba22 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-defines.h +++ b/drivers/media/video/cx25821/cx25821-medusa-defines.h @@ -23,7 +23,7 @@ #ifndef _MEDUSA_DEF_H_ #define _MEDUSA_DEF_H_ -/* Video deocder that we supported */ +/* Video decoder that we supported */ #define VDEC_A 0 #define VDEC_B 1 #define VDEC_C 2 @@ -34,9 +34,9 @@ #define VDEC_H 7 /* end of display sequence */ -#define END_OF_SEQ 0xF; +#define END_OF_SEQ 0xF; /* registry string size */ -#define MAX_REGISTRY_SZ 40; +#define MAX_REGISTRY_SZ 40; #endif diff --git a/drivers/media/video/cx25821/cx25821-medusa-reg.h b/drivers/media/video/cx25821/cx25821-medusa-reg.h index 1c1c228352d1..c98ac946b277 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-reg.h +++ b/drivers/media/video/cx25821/cx25821-medusa-reg.h @@ -28,22 +28,22 @@ #define HOST_REGISTER2 0x0001 /* Chip Configuration Registers */ -#define CHIP_CTRL 0x0100 -#define AFE_AB_CTRL 0x0104 -#define AFE_CD_CTRL 0x0108 -#define AFE_EF_CTRL 0x010C -#define AFE_GH_CTRL 0x0110 +#define CHIP_CTRL 0x0100 +#define AFE_AB_CTRL 0x0104 +#define AFE_CD_CTRL 0x0108 +#define AFE_EF_CTRL 0x010C +#define AFE_GH_CTRL 0x0110 #define DENC_AB_CTRL 0x0114 -#define BYP_AB_CTRL 0x0118 -#define MON_A_CTRL 0x011C -#define DISP_SEQ_A 0x0120 -#define DISP_SEQ_B 0x0124 -#define DISP_AB_CNT 0x0128 -#define DISP_CD_CNT 0x012C -#define DISP_EF_CNT 0x0130 -#define DISP_GH_CNT 0x0134 -#define DISP_IJ_CNT 0x0138 -#define PIN_OE_CTRL 0x013C +#define BYP_AB_CTRL 0x0118 +#define MON_A_CTRL 0x011C +#define DISP_SEQ_A 0x0120 +#define DISP_SEQ_B 0x0124 +#define DISP_AB_CNT 0x0128 +#define DISP_CD_CNT 0x012C +#define DISP_EF_CNT 0x0130 +#define DISP_GH_CNT 0x0134 +#define DISP_IJ_CNT 0x0138 +#define PIN_OE_CTRL 0x013C #define PIN_SPD_CTRL 0x0140 #define PIN_SPD_CTRL2 0x0144 #define IRQ_STAT_CTRL 0x0148 @@ -51,8 +51,8 @@ #define POWER_CTRL_CD 0x0150 #define POWER_CTRL_EF 0x0154 #define POWER_CTRL_GH 0x0158 -#define TUNE_CTRL 0x015C -#define BIAS_CTRL 0x0160 +#define TUNE_CTRL 0x015C +#define BIAS_CTRL 0x0160 #define AFE_AB_DIAG_CTRL 0x0164 #define AFE_CD_DIAG_CTRL 0x0168 #define AFE_EF_DIAG_CTRL 0x016C @@ -61,17 +61,17 @@ #define PLL_CD_DIAG_CTRL 0x0178 #define PLL_EF_DIAG_CTRL 0x017C #define PLL_GH_DIAG_CTRL 0x0180 -#define TEST_CTRL 0x0184 -#define BIST_STAT 0x0188 -#define BIST_STAT2 0x018C -#define BIST_VID_PLL_AB_STAT 0x0190 -#define BIST_VID_PLL_CD_STAT 0x0194 -#define BIST_VID_PLL_EF_STAT 0x0198 -#define BIST_VID_PLL_GH_STAT 0x019C +#define TEST_CTRL 0x0184 +#define BIST_STAT 0x0188 +#define BIST_STAT2 0x018C +#define BIST_VID_PLL_AB_STAT 0x0190 +#define BIST_VID_PLL_CD_STAT 0x0194 +#define BIST_VID_PLL_EF_STAT 0x0198 +#define BIST_VID_PLL_GH_STAT 0x019C #define DLL_DIAG_CTRL 0x01A0 #define DEV_CH_ID_CTRL 0x01A4 #define ABIST_CTRL_STATUS 0x01A8 -#define ABIST_FREQ 0x01AC +#define ABIST_FREQ 0x01AC #define ABIST_GOERT_SHIFT 0x01B0 #define ABIST_COEF12 0x01B4 #define ABIST_COEF34 0x01B8 @@ -92,357 +92,357 @@ #define ABIST_CLAMP_E 0x01F4 #define ABIST_CLAMP_F 0x01F8 -/* Digital Video Encoder A Registers */ -#define DENC_A_REG_1 0x0200 -#define DENC_A_REG_2 0x0204 -#define DENC_A_REG_3 0x0208 -#define DENC_A_REG_4 0x020C -#define DENC_A_REG_5 0x0210 -#define DENC_A_REG_6 0x0214 -#define DENC_A_REG_7 0x0218 -#define DENC_A_REG_8 0x021C +/* Digital Video Encoder A Registers */ +#define DENC_A_REG_1 0x0200 +#define DENC_A_REG_2 0x0204 +#define DENC_A_REG_3 0x0208 +#define DENC_A_REG_4 0x020C +#define DENC_A_REG_5 0x0210 +#define DENC_A_REG_6 0x0214 +#define DENC_A_REG_7 0x0218 +#define DENC_A_REG_8 0x021C -/* Digital Video Encoder B Registers */ -#define DENC_B_REG_1 0x0300 -#define DENC_B_REG_2 0x0304 -#define DENC_B_REG_3 0x0308 -#define DENC_B_REG_4 0x030C -#define DENC_B_REG_5 0x0310 -#define DENC_B_REG_6 0x0314 -#define DENC_B_REG_7 0x0318 -#define DENC_B_REG_8 0x031C +/* Digital Video Encoder B Registers */ +#define DENC_B_REG_1 0x0300 +#define DENC_B_REG_2 0x0304 +#define DENC_B_REG_3 0x0308 +#define DENC_B_REG_4 0x030C +#define DENC_B_REG_5 0x0310 +#define DENC_B_REG_6 0x0314 +#define DENC_B_REG_7 0x0318 +#define DENC_B_REG_8 0x031C -/* Video Decoder A Registers */ -#define MODE_CTRL 0x1000 -#define OUT_CTRL1 0x1004 -#define OUT_CTRL_NS 0x1008 -#define GEN_STAT 0x100C -#define INT_STAT_MASK 0x1010 -#define LUMA_CTRL 0x1014 -#define CHROMA_CTRL 0x1018 -#define CRUSH_CTRL 0x101C -#define HORIZ_TIM_CTRL 0x1020 -#define VERT_TIM_CTRL 0x1024 -#define MISC_TIM_CTRL 0x1028 -#define FIELD_COUNT 0x102C -#define HSCALE_CTRL 0x1030 -#define VSCALE_CTRL 0x1034 -#define MAN_VGA_CTRL 0x1038 -#define MAN_AGC_CTRL 0x103C -#define DFE_CTRL1 0x1040 -#define DFE_CTRL2 0x1044 -#define DFE_CTRL3 0x1048 -#define PLL_CTRL 0x104C -#define PLL_CTRL_FAST 0x1050 -#define HTL_CTRL 0x1054 -#define SRC_CFG 0x1058 -#define SC_STEP_SIZE 0x105C -#define SC_CONVERGE_CTRL 0x1060 -#define SC_LOOP_CTRL 0x1064 -#define COMB_2D_HFS_CFG 0x1068 -#define COMB_2D_HFD_CFG 0x106C -#define COMB_2D_LF_CFG 0x1070 -#define COMB_2D_BLEND 0x1074 -#define COMB_MISC_CTRL 0x1078 +/* Video Decoder A Registers */ +#define MODE_CTRL 0x1000 +#define OUT_CTRL1 0x1004 +#define OUT_CTRL_NS 0x1008 +#define GEN_STAT 0x100C +#define INT_STAT_MASK 0x1010 +#define LUMA_CTRL 0x1014 +#define CHROMA_CTRL 0x1018 +#define CRUSH_CTRL 0x101C +#define HORIZ_TIM_CTRL 0x1020 +#define VERT_TIM_CTRL 0x1024 +#define MISC_TIM_CTRL 0x1028 +#define FIELD_COUNT 0x102C +#define HSCALE_CTRL 0x1030 +#define VSCALE_CTRL 0x1034 +#define MAN_VGA_CTRL 0x1038 +#define MAN_AGC_CTRL 0x103C +#define DFE_CTRL1 0x1040 +#define DFE_CTRL2 0x1044 +#define DFE_CTRL3 0x1048 +#define PLL_CTRL 0x104C +#define PLL_CTRL_FAST 0x1050 +#define HTL_CTRL 0x1054 +#define SRC_CFG 0x1058 +#define SC_STEP_SIZE 0x105C +#define SC_CONVERGE_CTRL 0x1060 +#define SC_LOOP_CTRL 0x1064 +#define COMB_2D_HFS_CFG 0x1068 +#define COMB_2D_HFD_CFG 0x106C +#define COMB_2D_LF_CFG 0x1070 +#define COMB_2D_BLEND 0x1074 +#define COMB_MISC_CTRL 0x1078 #define COMB_FLAT_THRESH_CTRL 0x107C -#define COMB_TEST 0x1080 -#define BP_MISC_CTRL 0x1084 -#define VCR_DET_CTRL 0x1088 -#define NOISE_DET_CTRL 0x108C +#define COMB_TEST 0x1080 +#define BP_MISC_CTRL 0x1084 +#define VCR_DET_CTRL 0x1088 +#define NOISE_DET_CTRL 0x108C #define COMB_FLAT_NOISE_CTRL 0x1090 -#define VERSION 0x11F8 -#define SOFT_RST_CTRL 0x11FC +#define VERSION 0x11F8 +#define SOFT_RST_CTRL 0x11FC -/* Video Decoder B Registers */ -#define VDEC_B_MODE_CTRL 0x1200 -#define VDEC_B_OUT_CTRL1 0x1204 -#define VDEC_B_OUT_CTRL_NS 0x1208 -#define VDEC_B_GEN_STAT 0x120C +/* Video Decoder B Registers */ +#define VDEC_B_MODE_CTRL 0x1200 +#define VDEC_B_OUT_CTRL1 0x1204 +#define VDEC_B_OUT_CTRL_NS 0x1208 +#define VDEC_B_GEN_STAT 0x120C #define VDEC_B_INT_STAT_MASK 0x1210 -#define VDEC_B_LUMA_CTRL 0x1214 -#define VDEC_B_CHROMA_CTRL 0x1218 -#define VDEC_B_CRUSH_CTRL 0x121C +#define VDEC_B_LUMA_CTRL 0x1214 +#define VDEC_B_CHROMA_CTRL 0x1218 +#define VDEC_B_CRUSH_CTRL 0x121C #define VDEC_B_HORIZ_TIM_CTRL 0x1220 #define VDEC_B_VERT_TIM_CTRL 0x1224 #define VDEC_B_MISC_TIM_CTRL 0x1228 -#define VDEC_B_FIELD_COUNT 0x122C -#define VDEC_B_HSCALE_CTRL 0x1230 -#define VDEC_B_VSCALE_CTRL 0x1234 -#define VDEC_B_MAN_VGA_CTRL 0x1238 -#define VDEC_B_MAN_AGC_CTRL 0x123C -#define VDEC_B_DFE_CTRL1 0x1240 -#define VDEC_B_DFE_CTRL2 0x1244 -#define VDEC_B_DFE_CTRL3 0x1248 -#define VDEC_B_PLL_CTRL 0x124C +#define VDEC_B_FIELD_COUNT 0x122C +#define VDEC_B_HSCALE_CTRL 0x1230 +#define VDEC_B_VSCALE_CTRL 0x1234 +#define VDEC_B_MAN_VGA_CTRL 0x1238 +#define VDEC_B_MAN_AGC_CTRL 0x123C +#define VDEC_B_DFE_CTRL1 0x1240 +#define VDEC_B_DFE_CTRL2 0x1244 +#define VDEC_B_DFE_CTRL3 0x1248 +#define VDEC_B_PLL_CTRL 0x124C #define VDEC_B_PLL_CTRL_FAST 0x1250 -#define VDEC_B_HTL_CTRL 0x1254 -#define VDEC_B_SRC_CFG 0x1258 -#define VDEC_B_SC_STEP_SIZE 0x125C +#define VDEC_B_HTL_CTRL 0x1254 +#define VDEC_B_SRC_CFG 0x1258 +#define VDEC_B_SC_STEP_SIZE 0x125C #define VDEC_B_SC_CONVERGE_CTRL 0x1260 -#define VDEC_B_SC_LOOP_CTRL 0x1264 +#define VDEC_B_SC_LOOP_CTRL 0x1264 #define VDEC_B_COMB_2D_HFS_CFG 0x1268 #define VDEC_B_COMB_2D_HFD_CFG 0x126C #define VDEC_B_COMB_2D_LF_CFG 0x1270 #define VDEC_B_COMB_2D_BLEND 0x1274 #define VDEC_B_COMB_MISC_CTRL 0x1278 -#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C -#define VDEC_B_COMB_TEST 0x1280 -#define VDEC_B_BP_MISC_CTRL 0x1284 -#define VDEC_B_VCR_DET_CTRL 0x1288 +#define VDEC_B_COMB_FLAT_THRESH_CTRL 0x127C +#define VDEC_B_COMB_TEST 0x1280 +#define VDEC_B_BP_MISC_CTRL 0x1284 +#define VDEC_B_VCR_DET_CTRL 0x1288 #define VDEC_B_NOISE_DET_CTRL 0x128C #define VDEC_B_COMB_FLAT_NOISE_CTRL 0x1290 -#define VDEC_B_VERSION 0x13F8 +#define VDEC_B_VERSION 0x13F8 #define VDEC_B_SOFT_RST_CTRL 0x13FC /* Video Decoder C Registers */ -#define VDEC_C_MODE_CTRL 0x1400 -#define VDEC_C_OUT_CTRL1 0x1404 -#define VDEC_C_OUT_CTRL_NS 0x1408 -#define VDEC_C_GEN_STAT 0x140C +#define VDEC_C_MODE_CTRL 0x1400 +#define VDEC_C_OUT_CTRL1 0x1404 +#define VDEC_C_OUT_CTRL_NS 0x1408 +#define VDEC_C_GEN_STAT 0x140C #define VDEC_C_INT_STAT_MASK 0x1410 -#define VDEC_C_LUMA_CTRL 0x1414 -#define VDEC_C_CHROMA_CTRL 0x1418 -#define VDEC_C_CRUSH_CTRL 0x141C +#define VDEC_C_LUMA_CTRL 0x1414 +#define VDEC_C_CHROMA_CTRL 0x1418 +#define VDEC_C_CRUSH_CTRL 0x141C #define VDEC_C_HORIZ_TIM_CTRL 0x1420 #define VDEC_C_VERT_TIM_CTRL 0x1424 #define VDEC_C_MISC_TIM_CTRL 0x1428 -#define VDEC_C_FIELD_COUNT 0x142C -#define VDEC_C_HSCALE_CTRL 0x1430 -#define VDEC_C_VSCALE_CTRL 0x1434 -#define VDEC_C_MAN_VGA_CTRL 0x1438 -#define VDEC_C_MAN_AGC_CTRL 0x143C -#define VDEC_C_DFE_CTRL1 0x1440 -#define VDEC_C_DFE_CTRL2 0x1444 -#define VDEC_C_DFE_CTRL3 0x1448 -#define VDEC_C_PLL_CTRL 0x144C +#define VDEC_C_FIELD_COUNT 0x142C +#define VDEC_C_HSCALE_CTRL 0x1430 +#define VDEC_C_VSCALE_CTRL 0x1434 +#define VDEC_C_MAN_VGA_CTRL 0x1438 +#define VDEC_C_MAN_AGC_CTRL 0x143C +#define VDEC_C_DFE_CTRL1 0x1440 +#define VDEC_C_DFE_CTRL2 0x1444 +#define VDEC_C_DFE_CTRL3 0x1448 +#define VDEC_C_PLL_CTRL 0x144C #define VDEC_C_PLL_CTRL_FAST 0x1450 -#define VDEC_C_HTL_CTRL 0x1454 -#define VDEC_C_SRC_CFG 0x1458 -#define VDEC_C_SC_STEP_SIZE 0x145C +#define VDEC_C_HTL_CTRL 0x1454 +#define VDEC_C_SRC_CFG 0x1458 +#define VDEC_C_SC_STEP_SIZE 0x145C #define VDEC_C_SC_CONVERGE_CTRL 0x1460 -#define VDEC_C_SC_LOOP_CTRL 0x1464 +#define VDEC_C_SC_LOOP_CTRL 0x1464 #define VDEC_C_COMB_2D_HFS_CFG 0x1468 #define VDEC_C_COMB_2D_HFD_CFG 0x146C #define VDEC_C_COMB_2D_LF_CFG 0x1470 #define VDEC_C_COMB_2D_BLEND 0x1474 #define VDEC_C_COMB_MISC_CTRL 0x1478 -#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C -#define VDEC_C_COMB_TEST 0x1480 -#define VDEC_C_BP_MISC_CTRL 0x1484 -#define VDEC_C_VCR_DET_CTRL 0x1488 +#define VDEC_C_COMB_FLAT_THRESH_CTRL 0x147C +#define VDEC_C_COMB_TEST 0x1480 +#define VDEC_C_BP_MISC_CTRL 0x1484 +#define VDEC_C_VCR_DET_CTRL 0x1488 #define VDEC_C_NOISE_DET_CTRL 0x148C #define VDEC_C_COMB_FLAT_NOISE_CTRL 0x1490 -#define VDEC_C_VERSION 0x15F8 +#define VDEC_C_VERSION 0x15F8 #define VDEC_C_SOFT_RST_CTRL 0x15FC /* Video Decoder D Registers */ -#define VDEC_D_MODE_CTRL 0x1600 -#define VDEC_D_OUT_CTRL1 0x1604 -#define VDEC_D_OUT_CTRL_NS 0x1608 -#define VDEC_D_GEN_STAT 0x160C +#define VDEC_D_MODE_CTRL 0x1600 +#define VDEC_D_OUT_CTRL1 0x1604 +#define VDEC_D_OUT_CTRL_NS 0x1608 +#define VDEC_D_GEN_STAT 0x160C #define VDEC_D_INT_STAT_MASK 0x1610 -#define VDEC_D_LUMA_CTRL 0x1614 -#define VDEC_D_CHROMA_CTRL 0x1618 -#define VDEC_D_CRUSH_CTRL 0x161C +#define VDEC_D_LUMA_CTRL 0x1614 +#define VDEC_D_CHROMA_CTRL 0x1618 +#define VDEC_D_CRUSH_CTRL 0x161C #define VDEC_D_HORIZ_TIM_CTRL 0x1620 #define VDEC_D_VERT_TIM_CTRL 0x1624 #define VDEC_D_MISC_TIM_CTRL 0x1628 -#define VDEC_D_FIELD_COUNT 0x162C -#define VDEC_D_HSCALE_CTRL 0x1630 -#define VDEC_D_VSCALE_CTRL 0x1634 -#define VDEC_D_MAN_VGA_CTRL 0x1638 -#define VDEC_D_MAN_AGC_CTRL 0x163C -#define VDEC_D_DFE_CTRL1 0x1640 -#define VDEC_D_DFE_CTRL2 0x1644 -#define VDEC_D_DFE_CTRL3 0x1648 -#define VDEC_D_PLL_CTRL 0x164C +#define VDEC_D_FIELD_COUNT 0x162C +#define VDEC_D_HSCALE_CTRL 0x1630 +#define VDEC_D_VSCALE_CTRL 0x1634 +#define VDEC_D_MAN_VGA_CTRL 0x1638 +#define VDEC_D_MAN_AGC_CTRL 0x163C +#define VDEC_D_DFE_CTRL1 0x1640 +#define VDEC_D_DFE_CTRL2 0x1644 +#define VDEC_D_DFE_CTRL3 0x1648 +#define VDEC_D_PLL_CTRL 0x164C #define VDEC_D_PLL_CTRL_FAST 0x1650 -#define VDEC_D_HTL_CTRL 0x1654 -#define VDEC_D_SRC_CFG 0x1658 -#define VDEC_D_SC_STEP_SIZE 0x165C +#define VDEC_D_HTL_CTRL 0x1654 +#define VDEC_D_SRC_CFG 0x1658 +#define VDEC_D_SC_STEP_SIZE 0x165C #define VDEC_D_SC_CONVERGE_CTRL 0x1660 -#define VDEC_D_SC_LOOP_CTRL 0x1664 +#define VDEC_D_SC_LOOP_CTRL 0x1664 #define VDEC_D_COMB_2D_HFS_CFG 0x1668 #define VDEC_D_COMB_2D_HFD_CFG 0x166C #define VDEC_D_COMB_2D_LF_CFG 0x1670 #define VDEC_D_COMB_2D_BLEND 0x1674 #define VDEC_D_COMB_MISC_CTRL 0x1678 -#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C -#define VDEC_D_COMB_TEST 0x1680 -#define VDEC_D_BP_MISC_CTRL 0x1684 -#define VDEC_D_VCR_DET_CTRL 0x1688 +#define VDEC_D_COMB_FLAT_THRESH_CTRL 0x167C +#define VDEC_D_COMB_TEST 0x1680 +#define VDEC_D_BP_MISC_CTRL 0x1684 +#define VDEC_D_VCR_DET_CTRL 0x1688 #define VDEC_D_NOISE_DET_CTRL 0x168C #define VDEC_D_COMB_FLAT_NOISE_CTRL 0x1690 -#define VDEC_D_VERSION 0x17F8 +#define VDEC_D_VERSION 0x17F8 #define VDEC_D_SOFT_RST_CTRL 0x17FC /* Video Decoder E Registers */ -#define VDEC_E_MODE_CTRL 0x1800 -#define VDEC_E_OUT_CTRL1 0x1804 -#define VDEC_E_OUT_CTRL_NS 0x1808 -#define VDEC_E_GEN_STAT 0x180C +#define VDEC_E_MODE_CTRL 0x1800 +#define VDEC_E_OUT_CTRL1 0x1804 +#define VDEC_E_OUT_CTRL_NS 0x1808 +#define VDEC_E_GEN_STAT 0x180C #define VDEC_E_INT_STAT_MASK 0x1810 -#define VDEC_E_LUMA_CTRL 0x1814 -#define VDEC_E_CHROMA_CTRL 0x1818 -#define VDEC_E_CRUSH_CTRL 0x181C +#define VDEC_E_LUMA_CTRL 0x1814 +#define VDEC_E_CHROMA_CTRL 0x1818 +#define VDEC_E_CRUSH_CTRL 0x181C #define VDEC_E_HORIZ_TIM_CTRL 0x1820 #define VDEC_E_VERT_TIM_CTRL 0x1824 #define VDEC_E_MISC_TIM_CTRL 0x1828 -#define VDEC_E_FIELD_COUNT 0x182C -#define VDEC_E_HSCALE_CTRL 0x1830 -#define VDEC_E_VSCALE_CTRL 0x1834 -#define VDEC_E_MAN_VGA_CTRL 0x1838 -#define VDEC_E_MAN_AGC_CTRL 0x183C -#define VDEC_E_DFE_CTRL1 0x1840 -#define VDEC_E_DFE_CTRL2 0x1844 -#define VDEC_E_DFE_CTRL3 0x1848 -#define VDEC_E_PLL_CTRL 0x184C +#define VDEC_E_FIELD_COUNT 0x182C +#define VDEC_E_HSCALE_CTRL 0x1830 +#define VDEC_E_VSCALE_CTRL 0x1834 +#define VDEC_E_MAN_VGA_CTRL 0x1838 +#define VDEC_E_MAN_AGC_CTRL 0x183C +#define VDEC_E_DFE_CTRL1 0x1840 +#define VDEC_E_DFE_CTRL2 0x1844 +#define VDEC_E_DFE_CTRL3 0x1848 +#define VDEC_E_PLL_CTRL 0x184C #define VDEC_E_PLL_CTRL_FAST 0x1850 -#define VDEC_E_HTL_CTRL 0x1854 -#define VDEC_E_SRC_CFG 0x1858 -#define VDEC_E_SC_STEP_SIZE 0x185C +#define VDEC_E_HTL_CTRL 0x1854 +#define VDEC_E_SRC_CFG 0x1858 +#define VDEC_E_SC_STEP_SIZE 0x185C #define VDEC_E_SC_CONVERGE_CTRL 0x1860 -#define VDEC_E_SC_LOOP_CTRL 0x1864 +#define VDEC_E_SC_LOOP_CTRL 0x1864 #define VDEC_E_COMB_2D_HFS_CFG 0x1868 #define VDEC_E_COMB_2D_HFD_CFG 0x186C #define VDEC_E_COMB_2D_LF_CFG 0x1870 #define VDEC_E_COMB_2D_BLEND 0x1874 #define VDEC_E_COMB_MISC_CTRL 0x1878 -#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C -#define VDEC_E_COMB_TEST 0x1880 -#define VDEC_E_BP_MISC_CTRL 0x1884 -#define VDEC_E_VCR_DET_CTRL 0x1888 +#define VDEC_E_COMB_FLAT_THRESH_CTRL 0x187C +#define VDEC_E_COMB_TEST 0x1880 +#define VDEC_E_BP_MISC_CTRL 0x1884 +#define VDEC_E_VCR_DET_CTRL 0x1888 #define VDEC_E_NOISE_DET_CTRL 0x188C #define VDEC_E_COMB_FLAT_NOISE_CTRL 0x1890 -#define VDEC_E_VERSION 0x19F8 +#define VDEC_E_VERSION 0x19F8 #define VDEC_E_SOFT_RST_CTRL 0x19FC /* Video Decoder F Registers */ -#define VDEC_F_MODE_CTRL 0x1A00 -#define VDEC_F_OUT_CTRL1 0x1A04 -#define VDEC_F_OUT_CTRL_NS 0x1A08 -#define VDEC_F_GEN_STAT 0x1A0C +#define VDEC_F_MODE_CTRL 0x1A00 +#define VDEC_F_OUT_CTRL1 0x1A04 +#define VDEC_F_OUT_CTRL_NS 0x1A08 +#define VDEC_F_GEN_STAT 0x1A0C #define VDEC_F_INT_STAT_MASK 0x1A10 -#define VDEC_F_LUMA_CTRL 0x1A14 -#define VDEC_F_CHROMA_CTRL 0x1A18 -#define VDEC_F_CRUSH_CTRL 0x1A1C +#define VDEC_F_LUMA_CTRL 0x1A14 +#define VDEC_F_CHROMA_CTRL 0x1A18 +#define VDEC_F_CRUSH_CTRL 0x1A1C #define VDEC_F_HORIZ_TIM_CTRL 0x1A20 #define VDEC_F_VERT_TIM_CTRL 0x1A24 #define VDEC_F_MISC_TIM_CTRL 0x1A28 -#define VDEC_F_FIELD_COUNT 0x1A2C -#define VDEC_F_HSCALE_CTRL 0x1A30 -#define VDEC_F_VSCALE_CTRL 0x1A34 -#define VDEC_F_MAN_VGA_CTRL 0x1A38 -#define VDEC_F_MAN_AGC_CTRL 0x1A3C -#define VDEC_F_DFE_CTRL1 0x1A40 -#define VDEC_F_DFE_CTRL2 0x1A44 -#define VDEC_F_DFE_CTRL3 0x1A48 -#define VDEC_F_PLL_CTRL 0x1A4C +#define VDEC_F_FIELD_COUNT 0x1A2C +#define VDEC_F_HSCALE_CTRL 0x1A30 +#define VDEC_F_VSCALE_CTRL 0x1A34 +#define VDEC_F_MAN_VGA_CTRL 0x1A38 +#define VDEC_F_MAN_AGC_CTRL 0x1A3C +#define VDEC_F_DFE_CTRL1 0x1A40 +#define VDEC_F_DFE_CTRL2 0x1A44 +#define VDEC_F_DFE_CTRL3 0x1A48 +#define VDEC_F_PLL_CTRL 0x1A4C #define VDEC_F_PLL_CTRL_FAST 0x1A50 -#define VDEC_F_HTL_CTRL 0x1A54 -#define VDEC_F_SRC_CFG 0x1A58 -#define VDEC_F_SC_STEP_SIZE 0x1A5C +#define VDEC_F_HTL_CTRL 0x1A54 +#define VDEC_F_SRC_CFG 0x1A58 +#define VDEC_F_SC_STEP_SIZE 0x1A5C #define VDEC_F_SC_CONVERGE_CTRL 0x1A60 -#define VDEC_F_SC_LOOP_CTRL 0x1A64 +#define VDEC_F_SC_LOOP_CTRL 0x1A64 #define VDEC_F_COMB_2D_HFS_CFG 0x1A68 #define VDEC_F_COMB_2D_HFD_CFG 0x1A6C #define VDEC_F_COMB_2D_LF_CFG 0x1A70 #define VDEC_F_COMB_2D_BLEND 0x1A74 #define VDEC_F_COMB_MISC_CTRL 0x1A78 -#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C -#define VDEC_F_COMB_TEST 0x1A80 -#define VDEC_F_BP_MISC_CTRL 0x1A84 -#define VDEC_F_VCR_DET_CTRL 0x1A88 +#define VDEC_F_COMB_FLAT_THRESH_CTRL 0x1A7C +#define VDEC_F_COMB_TEST 0x1A80 +#define VDEC_F_BP_MISC_CTRL 0x1A84 +#define VDEC_F_VCR_DET_CTRL 0x1A88 #define VDEC_F_NOISE_DET_CTRL 0x1A8C #define VDEC_F_COMB_FLAT_NOISE_CTRL 0x1A90 -#define VDEC_F_VERSION 0x1BF8 +#define VDEC_F_VERSION 0x1BF8 #define VDEC_F_SOFT_RST_CTRL 0x1BFC /* Video Decoder G Registers */ -#define VDEC_G_MODE_CTRL 0x1C00 -#define VDEC_G_OUT_CTRL1 0x1C04 -#define VDEC_G_OUT_CTRL_NS 0x1C08 -#define VDEC_G_GEN_STAT 0x1C0C +#define VDEC_G_MODE_CTRL 0x1C00 +#define VDEC_G_OUT_CTRL1 0x1C04 +#define VDEC_G_OUT_CTRL_NS 0x1C08 +#define VDEC_G_GEN_STAT 0x1C0C #define VDEC_G_INT_STAT_MASK 0x1C10 -#define VDEC_G_LUMA_CTRL 0x1C14 -#define VDEC_G_CHROMA_CTRL 0x1C18 -#define VDEC_G_CRUSH_CTRL 0x1C1C +#define VDEC_G_LUMA_CTRL 0x1C14 +#define VDEC_G_CHROMA_CTRL 0x1C18 +#define VDEC_G_CRUSH_CTRL 0x1C1C #define VDEC_G_HORIZ_TIM_CTRL 0x1C20 #define VDEC_G_VERT_TIM_CTRL 0x1C24 #define VDEC_G_MISC_TIM_CTRL 0x1C28 -#define VDEC_G_FIELD_COUNT 0x1C2C -#define VDEC_G_HSCALE_CTRL 0x1C30 -#define VDEC_G_VSCALE_CTRL 0x1C34 -#define VDEC_G_MAN_VGA_CTRL 0x1C38 -#define VDEC_G_MAN_AGC_CTRL 0x1C3C -#define VDEC_G_DFE_CTRL1 0x1C40 -#define VDEC_G_DFE_CTRL2 0x1C44 -#define VDEC_G_DFE_CTRL3 0x1C48 -#define VDEC_G_PLL_CTRL 0x1C4C +#define VDEC_G_FIELD_COUNT 0x1C2C +#define VDEC_G_HSCALE_CTRL 0x1C30 +#define VDEC_G_VSCALE_CTRL 0x1C34 +#define VDEC_G_MAN_VGA_CTRL 0x1C38 +#define VDEC_G_MAN_AGC_CTRL 0x1C3C +#define VDEC_G_DFE_CTRL1 0x1C40 +#define VDEC_G_DFE_CTRL2 0x1C44 +#define VDEC_G_DFE_CTRL3 0x1C48 +#define VDEC_G_PLL_CTRL 0x1C4C #define VDEC_G_PLL_CTRL_FAST 0x1C50 -#define VDEC_G_HTL_CTRL 0x1C54 -#define VDEC_G_SRC_CFG 0x1C58 -#define VDEC_G_SC_STEP_SIZE 0x1C5C +#define VDEC_G_HTL_CTRL 0x1C54 +#define VDEC_G_SRC_CFG 0x1C58 +#define VDEC_G_SC_STEP_SIZE 0x1C5C #define VDEC_G_SC_CONVERGE_CTRL 0x1C60 -#define VDEC_G_SC_LOOP_CTRL 0x1C64 +#define VDEC_G_SC_LOOP_CTRL 0x1C64 #define VDEC_G_COMB_2D_HFS_CFG 0x1C68 #define VDEC_G_COMB_2D_HFD_CFG 0x1C6C #define VDEC_G_COMB_2D_LF_CFG 0x1C70 #define VDEC_G_COMB_2D_BLEND 0x1C74 #define VDEC_G_COMB_MISC_CTRL 0x1C78 -#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C -#define VDEC_G_COMB_TEST 0x1C80 -#define VDEC_G_BP_MISC_CTRL 0x1C84 -#define VDEC_G_VCR_DET_CTRL 0x1C88 +#define VDEC_G_COMB_FLAT_THRESH_CTRL 0x1C7C +#define VDEC_G_COMB_TEST 0x1C80 +#define VDEC_G_BP_MISC_CTRL 0x1C84 +#define VDEC_G_VCR_DET_CTRL 0x1C88 #define VDEC_G_NOISE_DET_CTRL 0x1C8C #define VDEC_G_COMB_FLAT_NOISE_CTRL 0x1C90 -#define VDEC_G_VERSION 0x1DF8 +#define VDEC_G_VERSION 0x1DF8 #define VDEC_G_SOFT_RST_CTRL 0x1DFC -/* Video Decoder H Registers */ -#define VDEC_H_MODE_CTRL 0x1E00 -#define VDEC_H_OUT_CTRL1 0x1E04 -#define VDEC_H_OUT_CTRL_NS 0x1E08 -#define VDEC_H_GEN_STAT 0x1E0C +/* Video Decoder H Registers */ +#define VDEC_H_MODE_CTRL 0x1E00 +#define VDEC_H_OUT_CTRL1 0x1E04 +#define VDEC_H_OUT_CTRL_NS 0x1E08 +#define VDEC_H_GEN_STAT 0x1E0C #define VDEC_H_INT_STAT_MASK 0x1E1E -#define VDEC_H_LUMA_CTRL 0x1E14 -#define VDEC_H_CHROMA_CTRL 0x1E18 -#define VDEC_H_CRUSH_CTRL 0x1E1C +#define VDEC_H_LUMA_CTRL 0x1E14 +#define VDEC_H_CHROMA_CTRL 0x1E18 +#define VDEC_H_CRUSH_CTRL 0x1E1C #define VDEC_H_HORIZ_TIM_CTRL 0x1E20 #define VDEC_H_VERT_TIM_CTRL 0x1E24 #define VDEC_H_MISC_TIM_CTRL 0x1E28 -#define VDEC_H_FIELD_COUNT 0x1E2C -#define VDEC_H_HSCALE_CTRL 0x1E30 -#define VDEC_H_VSCALE_CTRL 0x1E34 -#define VDEC_H_MAN_VGA_CTRL 0x1E38 -#define VDEC_H_MAN_AGC_CTRL 0x1E3C -#define VDEC_H_DFE_CTRL1 0x1E40 -#define VDEC_H_DFE_CTRL2 0x1E44 -#define VDEC_H_DFE_CTRL3 0x1E48 -#define VDEC_H_PLL_CTRL 0x1E4C +#define VDEC_H_FIELD_COUNT 0x1E2C +#define VDEC_H_HSCALE_CTRL 0x1E30 +#define VDEC_H_VSCALE_CTRL 0x1E34 +#define VDEC_H_MAN_VGA_CTRL 0x1E38 +#define VDEC_H_MAN_AGC_CTRL 0x1E3C +#define VDEC_H_DFE_CTRL1 0x1E40 +#define VDEC_H_DFE_CTRL2 0x1E44 +#define VDEC_H_DFE_CTRL3 0x1E48 +#define VDEC_H_PLL_CTRL 0x1E4C #define VDEC_H_PLL_CTRL_FAST 0x1E50 -#define VDEC_H_HTL_CTRL 0x1E54 -#define VDEC_H_SRC_CFG 0x1E58 -#define VDEC_H_SC_STEP_SIZE 0x1E5C +#define VDEC_H_HTL_CTRL 0x1E54 +#define VDEC_H_SRC_CFG 0x1E58 +#define VDEC_H_SC_STEP_SIZE 0x1E5C #define VDEC_H_SC_CONVERGE_CTRL 0x1E60 -#define VDEC_H_SC_LOOP_CTRL 0x1E64 +#define VDEC_H_SC_LOOP_CTRL 0x1E64 #define VDEC_H_COMB_2D_HFS_CFG 0x1E68 #define VDEC_H_COMB_2D_HFD_CFG 0x1E6C #define VDEC_H_COMB_2D_LF_CFG 0x1E70 #define VDEC_H_COMB_2D_BLEND 0x1E74 #define VDEC_H_COMB_MISC_CTRL 0x1E78 -#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C -#define VDEC_H_COMB_TEST 0x1E80 -#define VDEC_H_BP_MISC_CTRL 0x1E84 -#define VDEC_H_VCR_DET_CTRL 0x1E88 +#define VDEC_H_COMB_FLAT_THRESH_CTRL 0x1E7C +#define VDEC_H_COMB_TEST 0x1E80 +#define VDEC_H_BP_MISC_CTRL 0x1E84 +#define VDEC_H_VCR_DET_CTRL 0x1E88 #define VDEC_H_NOISE_DET_CTRL 0x1E8C #define VDEC_H_COMB_FLAT_NOISE_CTRL 0x1E90 -#define VDEC_H_VERSION 0x1FF8 +#define VDEC_H_VERSION 0x1FF8 #define VDEC_H_SOFT_RST_CTRL 0x1FFC /*****************************************************************************/ /* LUMA_CTRL register fields */ -#define VDEC_A_BRITE_CTRL 0x1014 +#define VDEC_A_BRITE_CTRL 0x1014 #define VDEC_A_CNTRST_CTRL 0x1015 #define VDEC_A_PEAK_SEL 0x1016 diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c index fc780d0908dc..298a68d98c2f 100644 --- a/drivers/media/video/cx25821/cx25821-medusa-video.c +++ b/drivers/media/video/cx25821/cx25821-medusa-video.c @@ -99,82 +99,67 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev) for (i = 0; i < MAX_DECODERS; i++) { /* set video format NTSC-M */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), &tmp); value &= 0xFFFFFFF0; /* enable the fast locking mode bit[16] */ value |= 0x10001; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), value); /* resolution NTSC 720x480 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x612D0074; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x1C1E001A; /* vblank_cnt + 2 to get camera ID */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), value); /* chroma subcarrier step size */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - SC_STEP_SIZE + (0x200 * i), 0x43E00000); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + SC_STEP_SIZE + (0x200 * i), 0x43E00000); /* enable VIP optional active */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), value); /* enable VIP optional active (VIP_OPT_AL) for direct output. */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), value); /* * clear VPRES_VERT_EN bit, fixes the chroma run away problem * when the input switching rate < 16 fields */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), &tmp); /* disable special play detection */ value = setBitAtPos(value, 14); value = clearBitAtPos(value, 15); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), value); /* set vbi_gate_en to 0 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), &tmp); value = clearBitAtPos(value, 29); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), value); /* Enable the generation of blue field output if no video */ medusa_enable_bluefield_output(dev, i, 1); @@ -182,61 +167,49 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev) for (i = 0; i < MAX_ENCODERS; i++) { /* NTSC hclock */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), &tmp); value &= 0xF000FC00; value |= 0x06B402D0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), value); /* burst begin and burst end */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), &tmp); value &= 0xFF000000; value |= 0x007E9054; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), &tmp); value &= 0xFC00FE00; value |= 0x00EC00F0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), value); /* set NTSC vblank, no phase alternation, 7.5 IRE pedestal */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), &tmp); value &= 0x00FCFFFF; value |= 0x13020000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), &tmp); value &= 0xFFFF0000; value |= 0x0000E575; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), value); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_6 + (0x100 * i), 0x009A89C1); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_6 + (0x100 * i), 0x009A89C1); /* Subcarrier Increment */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_7 + (0x100 * i), 0x21F07C1F); } /* set picture resolutions */ @@ -261,34 +234,27 @@ static int medusa_PALCombInit(struct cx25821_dev *dev, int dec) u32 value = 0, tmp = 0; /* Setup for 2D threshold */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFS_CFG + (0x200 * dec), - 0x20002861); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_HFD_CFG + (0x200 * dec), - 0x20002861); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_LF_CFG + (0x200 * dec), - 0x200A1023); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_HFS_CFG + (0x200 * dec), 0x20002861); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_HFD_CFG + (0x200 * dec), 0x20002861); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_LF_CFG + (0x200 * dec), 0x200A1023); /* Setup flat chroma and luma thresholds */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + COMB_FLAT_THRESH_CTRL + (0x200 * dec), &tmp); value &= 0x06230000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_FLAT_THRESH_CTRL + (0x200 * dec), value); /* set comb 2D blend */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_2D_BLEND + (0x200 * dec), - 0x210F0F0F); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_2D_BLEND + (0x200 * dec), 0x210F0F0F); /* COMB MISC CONTROL */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], COMB_MISC_CTRL + (0x200 * dec), - 0x41120A7F); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + COMB_MISC_CTRL + (0x200 * dec), 0x41120A7F); return ret_val; } @@ -304,83 +270,68 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) for (i = 0; i < MAX_DECODERS; i++) { /* set video format PAL-BDGHI */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), &tmp); value &= 0xFFFFFFF0; /* enable the fast locking mode bit[16] */ value |= 0x10004; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], MODE_CTRL + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MODE_CTRL + (0x200 * i), value); /* resolution PAL 720x576 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x632D007D; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HORIZ_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HORIZ_TIM_CTRL + (0x200 * i), value); /* vblank656_cnt=x26, vactive_cnt=240h, vblank_cnt=x24 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), &tmp); value &= 0x00C00C00; value |= 0x28240026; /* vblank_cnt + 2 to get camera ID */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VERT_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VERT_TIM_CTRL + (0x200 * i), value); /* chroma subcarrier step size */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + SC_STEP_SIZE + (0x200 * i), 0x5411E2D0); /* enable VIP optional active */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - OUT_CTRL_NS + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL_NS + (0x200 * i), value); /* enable VIP optional active (VIP_OPT_AL) for direct output. */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), &tmp); value &= 0xFFFBFFFF; value |= 0x00040000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], OUT_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + OUT_CTRL1 + (0x200 * i), value); /* * clear VPRES_VERT_EN bit, fixes the chroma run away problem * when the input switching rate < 16 fields */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), &tmp); /* disable special play detection */ value = setBitAtPos(value, 14); value = clearBitAtPos(value, 15); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - MISC_TIM_CTRL + (0x200 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + MISC_TIM_CTRL + (0x200 * i), value); /* set vbi_gate_en to 0 */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), &tmp); value = clearBitAtPos(value, 29); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], DFE_CTRL1 + (0x200 * i), - value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DFE_CTRL1 + (0x200 * i), value); medusa_PALCombInit(dev, i); @@ -390,62 +341,50 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) for (i = 0; i < MAX_ENCODERS; i++) { /* PAL hclock */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), &tmp); value &= 0xF000FC00; value |= 0x06C002D0; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_1 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_1 + (0x100 * i), value); /* burst begin and burst end */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), &tmp); value &= 0xFF000000; value |= 0x007E9754; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_2 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_2 + (0x100 * i), value); /* hblank and vactive */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), &tmp); value &= 0xFC00FE00; value |= 0x00FC0120; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_3 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_3 + (0x100 * i), value); /* set PAL vblank, phase alternation, 0 IRE pedestal */ - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), &tmp); value &= 0x00FCFFFF; value |= 0x14010000; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_4 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_4 + (0x100 * i), value); - value = - cx25821_i2c_read(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), &tmp); + value = cx25821_i2c_read(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), &tmp); value &= 0xFFFF0000; value |= 0x0000F078; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_5 + (0x100 * i), value); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_5 + (0x100 * i), value); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_6 + (0x100 * i), 0x00A493CF); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_6 + (0x100 * i), 0x00A493CF); /* Subcarrier Increment */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + DENC_A_REG_7 + (0x100 * i), 0x2A098ACB); } /* set picture resolutions */ @@ -499,7 +438,7 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width, mutex_lock(&dev->lock); - /* validate the width - cannot be negative */ + /* validate the width */ if (width > MAX_WIDTH) { pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n", __func__, width, MAX_WIDTH); @@ -543,12 +482,10 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width, for (; decoder < decoder_count; decoder++) { /* write scaling values for each decoder */ - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - HSCALE_CTRL + (0x200 * decoder), hscale); - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], - VSCALE_CTRL + (0x200 * decoder), vscale); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + HSCALE_CTRL + (0x200 * decoder), hscale); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], + VSCALE_CTRL + (0x200 * decoder), vscale); } mutex_unlock(&dev->lock); @@ -606,8 +543,8 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, } /* Map to Medusa register setting */ -static int mapM(int srcMin, - int srcMax, int srcVal, int dstMin, int dstMax, int *dstVal) +static int mapM(int srcMin, int srcMax, int srcVal, int dstMin, int dstMax, + int *dstVal) { int numerator; int denominator; @@ -654,23 +591,19 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) u32 val = 0, tmp = 0; mutex_lock(&dev->lock); - if ((brightness > VIDEO_PROCAMP_MAX) - || (brightness < VIDEO_PROCAMP_MIN)) { + if ((brightness > VIDEO_PROCAMP_MAX) || + (brightness < VIDEO_PROCAMP_MIN)) { mutex_unlock(&dev->lock); return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, - SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, + SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); value = convert_to_twos(value, 8); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_BRITE_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_BRITE_CTRL + (0x200 * decoder), - val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; } @@ -688,17 +621,13 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, - UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, contrast, + UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_CNTRST_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_CNTRST_CTRL + (0x200 * decoder), - val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; @@ -717,19 +646,16 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, SIGNED_BYTE_MIN, - SIGNED_BYTE_MAX, &value); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, hue, + SIGNED_BYTE_MIN, SIGNED_BYTE_MAX, &value); value = convert_to_twos(value, 8); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_HUE_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; @@ -743,33 +669,26 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) mutex_lock(&dev->lock); - if ((saturation > VIDEO_PROCAMP_MAX) - || (saturation < VIDEO_PROCAMP_MIN)) { + if ((saturation > VIDEO_PROCAMP_MAX) || + (saturation < VIDEO_PROCAMP_MIN)) { mutex_unlock(&dev->lock); return -1; } - ret_val = - mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, - UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); + ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, saturation, + UNSIGNED_BYTE_MIN, UNSIGNED_BYTE_MAX, &value); - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_USAT_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_USAT_CTRL + (0x200 * decoder), - val | value); - - val = - cx25821_i2c_read(&dev->i2c_bus[0], - VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_USAT_CTRL + (0x200 * decoder), val | value); + + val = cx25821_i2c_read(&dev->i2c_bus[0], + VDEC_A_VSAT_CTRL + (0x200 * decoder), &tmp); val &= 0xFFFFFF00; - ret_val |= - cx25821_i2c_write(&dev->i2c_bus[0], - VDEC_A_VSAT_CTRL + (0x200 * decoder), - val | value); + ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], + VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value); mutex_unlock(&dev->lock); return ret_val; @@ -830,9 +749,8 @@ int medusa_video_init(struct cx25821_dev *dev) /* select AFE clock to output mode */ value = cx25821_i2c_read(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, &tmp); value &= 0x83FFFFFF; - ret_val = - cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, - value | 0x10000000); + ret_val = cx25821_i2c_write(&dev->i2c_bus[0], AFE_AB_DIAG_CTRL, + value | 0x10000000); if (ret_val < 0) goto error; diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c index 2a724ddfa53f..5a157cf4a95e 100644 --- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c @@ -65,9 +65,8 @@ static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) - || !(dev->_isNTSC_ch2)) { + if ((lines <= NTSC_FIELD_HEIGHT) || + (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { offset += dist_betwn_starts; } } @@ -85,7 +84,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, { unsigned int line, i; struct sram_channel *sram_ch = - dev->channels[dev->_channel2_upstream_select].sram_channels; + dev->channels[dev->_channel2_upstream_select].sram_channels; int dist_betwn_starts = bpl * 2; /* sync instruction */ @@ -103,9 +102,8 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, *(rp++) = cpu_to_le32(databuf_phys_addr + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) - || !(dev->_isNTSC_ch2)) { + if ((lines <= NTSC_FIELD_HEIGHT) || + (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { offset += dist_betwn_starts; } @@ -173,7 +171,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, fifo_enable = FIFO_DISABLE; - /* Even field */ + /* Even field */ rp = cx25821_risc_field_upstream_ch2(dev, rp, dev->_data_buf_phys_addr_ch2 + databuf_offset, bottom_offset, 0x200, bpl, singlefield_lines, @@ -189,9 +187,9 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, } /* - Loop to 2ndFrameRISC or to Start of - Risc program & generate IRQ - */ + * Loop to 2ndFrameRISC or to Start of + * Risc program & generate IRQ + */ *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); *(rp++) = cpu_to_le32(risc_phys_jump_addr); *(rp++) = cpu_to_le32(0); @@ -203,7 +201,7 @@ int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) { struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; + dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; u32 tmp = 0; if (!dev->_is_running_ch2) { @@ -262,9 +260,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) struct file *myfile; int frame_index_temp = dev->_frame_index_ch2; int i = 0; - int line_size = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; int frame_size = 0; int frame_offset = 0; ssize_t vfs_read_retval = 0; @@ -277,14 +274,11 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) return 0; if (dev->_isNTSC_ch2) { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; } else { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; } frame_offset = (frame_index_temp > 0) ? frame_size : 0; @@ -318,14 +312,14 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count_ch2; i++) { pos = file_offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size && dev->_data_buf_virt_addr_ch2 != NULL) { memcpy((void *)(dev->_data_buf_virt_addr_ch2 + frame_offset / 4), mybuf, - vfs_read_retval); + vfs_read_retval); } file_offset += vfs_read_retval; @@ -341,8 +335,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) if (i > 0) dev->_frame_count_ch2++; - dev->_file_status_ch2 = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status_ch2 = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); filp_close(myfile, NULL); @@ -353,8 +347,8 @@ int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) static void cx25821_vidups_handler_ch2(struct work_struct *work) { - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _irq_work_entry_ch2); + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _irq_work_entry_ch2); if (!dev) { pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", @@ -362,18 +356,16 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work) return; } - cx25821_get_frame_ch2(dev, - dev->channels[dev-> - _channel2_upstream_select].sram_channels); + cx25821_get_frame_ch2(dev, dev->channels[dev-> + _channel2_upstream_select].sram_channels); } int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; - int line_size = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; ssize_t vfs_read_retval = 0; char mybuf[line_size]; loff_t pos; @@ -410,16 +402,16 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count_ch2; i++) { pos = offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && dev->_data_buf_virt_addr_ch2 != NULL) { + if (vfs_read_retval > 0 && + vfs_read_retval == line_size && + dev->_data_buf_virt_addr_ch2 != NULL) { memcpy((void *)(dev-> _data_buf_virt_addr_ch2 + offset / 4), mybuf, - vfs_read_retval); + vfs_read_retval); } offset += vfs_read_retval; @@ -438,8 +430,8 @@ int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) break; } - dev->_file_status_ch2 = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status_ch2 = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); myfile->f_pos = 0; @@ -463,9 +455,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, dev->_dma_phys_addr_ch2); } - dev->_dma_virt_addr_ch2 = - pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, - &dma_addr); + dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci, + dev->upstream_riscbuf_size_ch2, &dma_addr); dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; dev->_dma_phys_start_addr_ch2 = dma_addr; dev->_dma_phys_addr_ch2 = dma_addr; @@ -485,9 +476,8 @@ static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, dev->_data_buf_phys_addr_ch2); } /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr_ch2 = - pci_alloc_consistent(dev->pci, dev->upstream_databuf_size_ch2, - &data_dma_addr); + dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci, + dev->upstream_databuf_size_ch2, &data_dma_addr); dev->_data_buf_phys_addr_ch2 = data_dma_addr; dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; @@ -563,8 +553,8 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, else line_size_in_bytes = Y422_LINE_SZ; risc_phys_jump_addr = - dev->_dma_phys_start_addr_ch2 + - odd_risc_prog_size; + dev->_dma_phys_start_addr_ch2 + + odd_risc_prog_size; rp = cx25821_update_riscprogram_ch2(dev, dev->_dma_virt_start_addr_ch2, @@ -612,11 +602,9 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) vid_status = cx_read(sram_ch->int_stat); /* Only deal with our interrupt */ - if (vid_status) { - handled = - cx25821_video_upstream_irq_ch2(dev, channel_num, - vid_status); - } + if (vid_status) + handled = cx25821_video_upstream_irq_ch2(dev, channel_num, + vid_status); if (handled < 0) cx25821_stop_upstream_video_ch2(dev); @@ -691,8 +679,7 @@ int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp |= _intr_msk); - err = - request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, + err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, IRQF_SHARED, dev->name, dev); if (err < 0) { pr_err("%s: can't get upstream IRQ %d\n", @@ -752,45 +739,38 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, dev->_file_status_ch2 = RESET_STATUS; dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; dev->_pixel_format_ch2 = pixel_format; - dev->_line_size_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = - dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; + risc_buffer_size = dev->_isNTSC_ch2 ? + NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; if (dev->input_filename_ch2) { str_length = strlen(dev->input_filename_ch2); - dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename_ch2 = kmemdup(dev->input_filename_ch2, + str_length + 1, GFP_KERNEL); if (!dev->_filename_ch2) goto error; - - memcpy(dev->_filename_ch2, dev->input_filename_ch2, - str_length + 1); } else { str_length = strlen(dev->_defaultname_ch2); - dev->_filename_ch2 = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2, + str_length + 1, GFP_KERNEL); if (!dev->_filename_ch2) goto error; - - memcpy(dev->_filename_ch2, dev->_defaultname_ch2, - str_length + 1); } /* Default if filename is empty string */ if (strcmp(dev->input_filename_ch2, "") == 0) { if (dev->_isNTSC_ch2) { - dev->_filename_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; + dev->_filename_ch2 = (dev->_pixel_format_ch2 == + PIXEL_FRMT_411) ? "/root/vid411.yuv" : + "/root/vidtest.yuv"; } else { - dev->_filename_ch2 = - (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; + dev->_filename_ch2 = (dev->_pixel_format_ch2 == + PIXEL_FRMT_411) ? "/root/pal411.yuv" : + "/root/pal422.yuv"; } } diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c index c0b80068f468..21e7d657f049 100644 --- a/drivers/media/video/cx25821/cx25821-video-upstream.c +++ b/drivers/media/video/cx25821/cx25821-video-upstream.c @@ -136,7 +136,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, { unsigned int line, i; struct sram_channel *sram_ch = - dev->channels[dev->_channel_upstream_select].sram_channels; + dev->channels[dev->_channel_upstream_select].sram_channels; int dist_betwn_starts = bpl * 2; /* sync instruction */ @@ -194,15 +194,12 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, if (dev->_isNTSC) { odd_num_lines = singlefield_lines + 1; risc_program_size = FRAME1_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; + frame_size = (bpl == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; } else { risc_program_size = PAL_VID_PROG_SIZE; - frame_size = - (bpl == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; + frame_size = (bpl == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; } /* Virtual address of Risc buffer program */ @@ -214,13 +211,9 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, if (UNSET != top_offset) { fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; rp = cx25821_risc_field_upstream(dev, rp, - dev-> - _data_buf_phys_addr + - databuf_offset, - top_offset, 0, bpl, - odd_num_lines, - fifo_enable, - ODD_FIELD); + dev->_data_buf_phys_addr + + databuf_offset, top_offset, 0, bpl, + odd_num_lines, fifo_enable, ODD_FIELD); } fifo_enable = FIFO_DISABLE; @@ -234,8 +227,8 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, if (frame == 0) { risc_flag = RISC_CNT_RESET; - risc_phys_jump_addr = - dev->_dma_phys_start_addr + risc_program_size; + risc_phys_jump_addr = dev->_dma_phys_start_addr + + risc_program_size; } else { risc_phys_jump_addr = dev->_dma_phys_start_addr; risc_flag = RISC_CNT_INC; @@ -255,7 +248,7 @@ int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) { struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; + dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; u32 tmp = 0; if (!dev->_is_running) { @@ -312,9 +305,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) struct file *myfile; int frame_index_temp = dev->_frame_index; int i = 0; - int line_size = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; int frame_size = 0; int frame_offset = 0; ssize_t vfs_read_retval = 0; @@ -326,16 +318,12 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) if (dev->_file_status == END_OF_FILE) return 0; - if (dev->_isNTSC) { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : - FRAME_SIZE_NTSC_Y422; - } else { - frame_size = - (line_size == - Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } + if (dev->_isNTSC) + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; + else + frame_size = (line_size == Y411_LINE_SZ) ? + FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; frame_offset = (frame_index_temp > 0) ? frame_size : 0; file_offset = dev->_frame_count * frame_size; @@ -369,8 +357,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count; i++) { pos = file_offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, line_size, + &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size && dev->_data_buf_virt_addr != NULL) { @@ -392,8 +380,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) if (i > 0) dev->_frame_count++; - dev->_file_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); filp_close(myfile, NULL); @@ -404,8 +392,8 @@ int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) static void cx25821_vidups_handler(struct work_struct *work) { - struct cx25821_dev *dev = - container_of(work, struct cx25821_dev, _irq_work_entry); + struct cx25821_dev *dev = container_of(work, struct cx25821_dev, + _irq_work_entry); if (!dev) { pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", @@ -413,18 +401,16 @@ static void cx25821_vidups_handler(struct work_struct *work) return; } - cx25821_get_frame(dev, - dev->channels[dev->_channel_upstream_select]. - sram_channels); + cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select]. + sram_channels); } int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; - int line_size = - (dev->_pixel_format == - PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; + int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + Y411_LINE_SZ : Y422_LINE_SZ; ssize_t vfs_read_retval = 0; char mybuf[line_size]; loff_t pos; @@ -461,8 +447,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) for (i = 0; i < dev->_lines_count; i++) { pos = offset; - vfs_read_retval = - vfs_read(myfile, mybuf, line_size, &pos); + vfs_read_retval = vfs_read(myfile, mybuf, + line_size, &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size @@ -489,8 +475,8 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) break; } - dev->_file_status = - (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; + dev->_file_status = (vfs_read_retval == line_size) ? + IN_PROGRESS : END_OF_FILE; set_fs(old_fs); myfile->f_pos = 0; @@ -507,14 +493,12 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, dma_addr_t dma_addr; dma_addr_t data_dma_addr; - if (dev->_dma_virt_addr != NULL) { + if (dev->_dma_virt_addr != NULL) pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, - dev->_dma_virt_addr, dev->_dma_phys_addr); - } + dev->_dma_virt_addr, dev->_dma_phys_addr); - dev->_dma_virt_addr = - pci_alloc_consistent(dev->pci, dev->upstream_riscbuf_size, - &dma_addr); + dev->_dma_virt_addr = pci_alloc_consistent(dev->pci, + dev->upstream_riscbuf_size, &dma_addr); dev->_dma_virt_start_addr = dev->_dma_virt_addr; dev->_dma_phys_start_addr = dma_addr; dev->_dma_phys_addr = dma_addr; @@ -528,15 +512,13 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, /* Clear memory at address */ memset(dev->_dma_virt_addr, 0, dev->_risc_size); - if (dev->_data_buf_virt_addr != NULL) { + if (dev->_data_buf_virt_addr != NULL) pci_free_consistent(dev->pci, dev->upstream_databuf_size, - dev->_data_buf_virt_addr, - dev->_data_buf_phys_addr); - } + dev->_data_buf_virt_addr, + dev->_data_buf_phys_addr); /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr = - pci_alloc_consistent(dev->pci, dev->upstream_databuf_size, - &data_dma_addr); + dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci, + dev->upstream_databuf_size, &data_dma_addr); dev->_data_buf_phys_addr = data_dma_addr; dev->_data_buf_size = dev->upstream_databuf_size; @@ -553,9 +535,8 @@ int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, return ret; /* Create RISC programs */ - ret = - cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, - dev->_lines_count); + ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, + dev->_lines_count); if (ret < 0) { pr_info("Failed creating Video Upstream Risc programs!\n"); goto error; @@ -672,10 +653,9 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) vid_status = cx_read(sram_ch->int_stat); /* Only deal with our interrupt */ - if (vid_status) { - handled = - cx25821_video_upstream_irq(dev, channel_num, vid_status); - } + if (vid_status) + handled = cx25821_video_upstream_irq(dev, channel_num, + vid_status); if (handled < 0) cx25821_stop_upstream_video_ch1(dev); @@ -747,8 +727,7 @@ int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp |= _intr_msk); - err = - request_irq(dev->pci->irq, cx25821_upstream_irq, + err = request_irq(dev->pci->irq, cx25821_upstream_irq, IRQF_SHARED, dev->name, dev); if (err < 0) { pr_err("%s: can't get upstream IRQ %d\n", @@ -807,43 +786,38 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->_file_status = RESET_STATUS; dev->_lines_count = dev->_isNTSC ? 480 : 576; dev->_pixel_format = pixel_format; - dev->_line_size = - (dev->_pixel_format == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = - dev->_isNTSC ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; + risc_buffer_size = dev->_isNTSC ? + NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; if (dev->input_filename) { str_length = strlen(dev->input_filename); - dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename = kmemdup(dev->input_filename, str_length + 1, + GFP_KERNEL); if (!dev->_filename) goto error; - - memcpy(dev->_filename, dev->input_filename, str_length + 1); } else { str_length = strlen(dev->_defaultname); - dev->_filename = kmalloc(str_length + 1, GFP_KERNEL); + dev->_filename = kmemdup(dev->_defaultname, str_length + 1, + GFP_KERNEL); if (!dev->_filename) goto error; - - memcpy(dev->_filename, dev->_defaultname, str_length + 1); } /* Default if filename is empty string */ if (strcmp(dev->input_filename, "") == 0) { if (dev->_isNTSC) { dev->_filename = - (dev->_pixel_format == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; + (dev->_pixel_format == PIXEL_FRMT_411) ? + "/root/vid411.yuv" : "/root/vidtest.yuv"; } else { dev->_filename = - (dev->_pixel_format == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; + (dev->_pixel_format == PIXEL_FRMT_411) ? + "/root/pal411.yuv" : "/root/pal422.yuv"; } } @@ -852,13 +826,11 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->_file_status = RESET_STATUS; dev->_lines_count = dev->_isNTSC ? 480 : 576; dev->_pixel_format = pixel_format; - dev->_line_size = - (dev->_pixel_format == - PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - retval = - cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size, - 0); + retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, + dev->_line_size, 0); /* setup fifo + format */ cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c index 4d6907cda75b..ffd8bc79c02e 100644 --- a/drivers/media/video/cx25821/cx25821-video.c +++ b/drivers/media/video/cx25821/cx25821-video.c @@ -118,12 +118,12 @@ void cx25821_dump_video_queue(struct cx25821_dev *dev, if (!list_empty(&q->active)) { list_for_each(item, &q->active) - buf = list_entry(item, struct cx25821_buffer, vb.queue); + buf = list_entry(item, struct cx25821_buffer, vb.queue); } if (!list_empty(&q->queued)) { list_for_each(item, &q->queued) - buf = list_entry(item, struct cx25821_buffer, vb.queue); + buf = list_entry(item, struct cx25821_buffer, vb.queue); } } @@ -140,8 +140,8 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, break; } - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); /* count comes from the hw and it is 16bit wide -- * this trick handles wrap-arounds correctly for @@ -318,8 +318,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev, struct list_head *item; if (!list_empty(&q->active)) { - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); cx25821_start_video_dma(dev, q, buf, channel); @@ -337,8 +337,8 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev, if (list_empty(&q->queued)) return 0; - buf = - list_entry(q->queued.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->queued.next, struct cx25821_buffer, + vb.queue); if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); @@ -375,8 +375,8 @@ void cx25821_vid_timeout(unsigned long data) spin_lock_irqsave(&dev->slock, flags); while (!list_empty(&q->active)) { - buf = - list_entry(q->active.next, struct cx25821_buffer, vb.queue); + buf = list_entry(q->active.next, struct cx25821_buffer, + vb.queue); list_del(&buf->vb.queue); buf->vb.state = VIDEOBUF_ERROR; @@ -484,8 +484,7 @@ int cx25821_video_register(struct cx25821_dev *dev) cx25821_init_controls(dev, i); cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, - dev->channels[i].sram_channels->dma_ctl, - 0x11, 0); + dev->channels[i].sram_channels->dma_ctl, 0x11, 0); dev->channels[i].sram_channels = &cx25821_sram_channels[i]; dev->channels[i].video_dev = NULL; @@ -499,15 +498,14 @@ int cx25821_video_register(struct cx25821_dev *dev) dev->channels[i].timeout_data.dev = dev; dev->channels[i].timeout_data.channel = &cx25821_sram_channels[i]; - dev->channels[i].vidq.timeout.function = - cx25821_vid_timeout; + dev->channels[i].vidq.timeout.function = cx25821_vid_timeout; dev->channels[i].vidq.timeout.data = (unsigned long)&dev->channels[i].timeout_data; init_timer(&dev->channels[i].vidq.timeout); /* register v4l devices */ - dev->channels[i].video_dev = cx25821_vdev_init(dev, - dev->pci, &cx25821_video_device, "video"); + dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_video_device, "video"); err = video_register_device(dev->channels[i].video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); @@ -528,7 +526,6 @@ int cx25821_video_register(struct cx25821_dev *dev) #endif mutex_unlock(&dev->lock); - return 0; fail_unreg: @@ -558,7 +555,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct cx25821_fh *fh = q->priv_data; struct cx25821_dev *dev = fh->dev; struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); + container_of(vb, struct cx25821_buffer, vb); int rc, init_buffer = 0; u32 line0_offset, line1_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); @@ -617,14 +614,13 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (channel_opened >= 0 && channel_opened <= 7) { if (dev->channels[channel_opened] .use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_PAL_BG - || dev->tvnorm & V4L2_STD_PAL_DK) + if (dev->tvnorm & V4L2_STD_PAL_BG || + dev->tvnorm & V4L2_STD_PAL_DK) bpl_local = 352 << 1; else - bpl_local = - dev->channels[channel_opened]. - cif_width << - 1; + bpl_local = dev->channels[ + channel_opened]. + cif_width << 1; } } } @@ -685,7 +681,7 @@ void cx25821_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); + container_of(vb, struct cx25821_buffer, vb); cx25821_free_buffer(q, buf); } @@ -723,7 +719,7 @@ int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct cx25821_buffer *buf = - container_of(vb, struct cx25821_buffer, vb); + container_of(vb, struct cx25821_buffer, vb); struct cx25821_buffer *prev; struct cx25821_fh *fh = vq->priv_data; struct cx25821_dev *dev = fh->dev; @@ -814,7 +810,7 @@ static int video_open(struct file *file) for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { if (h->channels[i].video_dev && - h->channels[i].video_dev->minor == minor) { + h->channels[i].video_dev->minor == minor) { dev = h; ch_id = i; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -848,11 +844,10 @@ static int video_open(struct file *file) v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); - videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx25821_buffer), fh, NULL); + videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev, + &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), + fh, NULL); dprintk(1, "post videobuf_queue_init()\n"); mutex_unlock(&cx25821_devlist_mutex); @@ -1168,8 +1163,8 @@ int cx25821_vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); cap->version = CX25821_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; if (UNSET != dev->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; @@ -1454,38 +1449,38 @@ static const struct v4l2_queryctrl no_ctl = { static struct v4l2_queryctrl cx25821_ctls[] = { /* --- video --- */ { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 6200, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - } + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 6200, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + }, { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 10000, + .step = 1, + .default_value = 5000, + .type = V4L2_CTRL_TYPE_INTEGER, + } }; static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls); @@ -1623,7 +1618,8 @@ int cx25821_vidioc_cropcap(struct file *file, void *priv, if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.top = 0; + cropcap->bounds.left = 0; cropcap->bounds.width = 720; cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480; cropcap->pixelaspect.numerator = @@ -1829,8 +1825,11 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, struct downstream_user_struct *data_from_user; int command; int width = 720; - int selected_channel = 0, pix_format = 0, i = 0; - int cif_enable = 0, cif_width = 0; + int selected_channel = 0; + int pix_format = 0; + int i = 0; + int cif_enable = 0; + int cif_width = 0; u32 value = 0; data_from_user = (struct downstream_user_struct *)arg; @@ -1895,8 +1894,8 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, } if (selected_channel <= 7 && selected_channel >= 0) { - dev->channels[selected_channel]. - use_cif_resolution = cif_enable; + dev->channels[selected_channel].use_cif_resolution = + cif_enable; dev->channels[selected_channel].cif_width = width; } else { for (i = 0; i < VID_CHANNEL_NUM; i++) { @@ -1932,9 +1931,9 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, static long cx25821_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - int ret = 0; + int ret = 0; - struct cx25821_fh *fh = file->private_data; + struct cx25821_fh *fh = file->private_data; /* check to see if it's the video upstream */ if (fh->channel_id == SRAM_CH09) { diff --git a/drivers/media/video/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index 2d2d00932823..b9aa801b00a7 100644 --- a/drivers/media/video/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h @@ -67,7 +67,7 @@ #define MAX_CAMERAS 16 /* Max number of inputs by card */ -#define MAX_CX25821_INPUT 8 +#define MAX_CX25821_INPUT 8 #define INPUT(nr) (&cx25821_boards[dev->board].input[nr]) #define RESOURCE_VIDEO0 1 #define RESOURCE_VIDEO1 2 @@ -85,7 +85,7 @@ #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ -#define UNKNOWN_BOARD 0 +#define UNKNOWN_BOARD 0 #define CX25821_BOARD 1 /* Currently supported by the driver */ diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 005f11093642..34b96c7cfd62 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -480,7 +480,6 @@ void cx25840_audio_set_path(struct i2c_client *client) static void set_volume(struct i2c_client *client, int volume) { - struct cx25840_state *state = to_state(i2c_get_clientdata(client)); int vol; /* Convert the volume to msp3400 values (0-127) */ @@ -496,14 +495,7 @@ static void set_volume(struct i2c_client *client, int volume) } /* PATH1_VOLUME */ - if (is_cx2388x(state)) { - /* for cx23885 volume doesn't work, - * the calculation always results in - * e4 regardless. - */ - cx25840_write(client, 0x8d4, volume); - } else - cx25840_write(client, 0x8d4, 228 - (vol * 2)); + cx25840_write(client, 0x8d4, 228 - (vol * 2)); } static void set_balance(struct i2c_client *client, int balance) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index cd9976408ab3..05247d4c340a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -18,6 +18,9 @@ * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net> * + * CX23888 DIF support for the HVR1850 + * Copyright (C) 2011 Steven Toth <stoth@kernellabs.com> + * * 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 @@ -40,6 +43,7 @@ #include <linux/videodev2.h> #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/math64.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/cx25840.h> @@ -80,6 +84,7 @@ MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); /* ----------------------------------------------------------------------- */ +static void cx23885_std_setup(struct i2c_client *client); int cx25840_write(struct i2c_client *client, u16 addr, u8 value) { @@ -498,8 +503,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - cx25840_write4(client, 0x11c, 0x00e8ba26); - cx25840_write4(client, 0x118, 0x0000040b); + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + cx25840_write4(client, 0x11c, 0x01d1744c); + cx25840_write4(client, 0x118, 0x00000416); + cx25840_write4(client, 0x404, 0x0010253e); + cx25840_write4(client, 0x42c, 0x42600000); + cx25840_write4(client, 0x44c, 0x161f1000); break; case V4L2_IDENT_CX23887_AV: /* @@ -533,8 +543,18 @@ static void cx23885_initialize(struct i2c_client *client) * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz * 432.0 MHz before post divide */ - cx25840_write4(client, 0x10c, 0x002be2c9); - cx25840_write4(client, 0x108, 0x0000040f); + + /* HVR1850 */ + switch (state->id) { + case V4L2_IDENT_CX23888_AV: + /* 888/HVR1250 specific */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + break; + default: + cx25840_write4(client, 0x10c, 0x002be2c9); + cx25840_write4(client, 0x108, 0x0000040f); + } /* Luma */ cx25840_write4(client, 0x414, 0x00107d12); @@ -556,8 +576,9 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - cx25840_write4(client, 0x114, 0x00bedfa4); - cx25840_write4(client, 0x110, 0x000a0307); + /* HVR1850 or 50MHz xtal */ + cx25840_write4(client, 0x114, 0x017dbf48); + cx25840_write4(client, 0x110, 0x000a030e); break; case V4L2_IDENT_CX23887_AV: /* @@ -617,7 +638,10 @@ static void cx23885_initialize(struct i2c_client *client) finish_wait(&state->fw_wait, &wait); destroy_workqueue(q); - cx25840_std_setup(client); + /* Call the cx23885 specific std setup func, we no longer rely on + * the generic cx24840 func. + */ + cx23885_std_setup(client); /* (re)set input */ set_input(client, state->vid_input, state->aud_input); @@ -631,6 +655,37 @@ static void cx23885_initialize(struct i2c_client *client) /* Disable and clear audio interrupts - we don't use them */ cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff); cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); + + /* CC raw enable */ + /* - VIP 1.1 control codes - 10bit, blue field enable. + * - enable raw data during vertical blanking. + * - enable ancillary Data insertion for 656 or VIP. + */ + cx25840_write4(client, 0x404, 0x0010253e); + + /* CC on - Undocumented Register */ + cx25840_write(client, 0x42f, 0x66); + + /* HVR-1250 / HVR1850 DIF related */ + /* Power everything up */ + cx25840_write4(client, 0x130, 0x0); + + /* Undocumented */ + cx25840_write4(client, 0x478, 0x6628021F); + + /* AFE_CLK_OUT_CTRL - Select the clock output source as output */ + cx25840_write4(client, 0x144, 0x5); + + /* I2C_OUT_CTL - I2S output configuration as + * Master, Sony, Left justified, left sample on WS=1 + */ + cx25840_write4(client, 0x918, 0x1a0); + + /* AFE_DIAG_CTRL1 */ + cx25840_write4(client, 0x134, 0x000a1800); + + /* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */ + cx25840_write4(client, 0x13c, 0x00310000); } /* ----------------------------------------------------------------------- */ @@ -945,9 +1000,14 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input <= CX25840_COMPOSITE8); u8 is_component = (vid_input & CX25840_COMPONENT_ON) == CX25840_COMPONENT_ON; + u8 is_dif = (vid_input & CX25840_DIF_ON) == + CX25840_DIF_ON; + u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) == + CX25840_SVIDEO_ON; int luma = vid_input & 0xf0; int chroma = vid_input & 0xf00; u8 reg; + u32 val; v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n", @@ -1012,6 +1072,66 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp else cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); + if (is_cx2388x(state)) { + + /* Enable or disable the DIF for tuner use */ + if (is_dif) { + cx25840_and_or(client, 0x102, ~0x80, 0x80); + + /* Set of defaults for NTSC and PAL */ + cx25840_write4(client, 0x31c, 0xc2262600); + cx25840_write4(client, 0x320, 0xc2262600); + + /* 18271 IF - Nobody else yet uses a different + * tuner with the DIF, so these are reasonable + * assumptions (HVR1250 and HVR1850 specific). + */ + cx25840_write4(client, 0x318, 0xda262600); + cx25840_write4(client, 0x33c, 0x2a24c800); + cx25840_write4(client, 0x104, 0x0704dd00); + } else { + cx25840_write4(client, 0x300, 0x015c28f5); + + cx25840_and_or(client, 0x102, ~0x80, 0); + cx25840_write4(client, 0x340, 0xdf7df83); + cx25840_write4(client, 0x104, 0x0704dd80); + cx25840_write4(client, 0x314, 0x22400600); + cx25840_write4(client, 0x318, 0x40002600); + cx25840_write4(client, 0x324, 0x40002600); + cx25840_write4(client, 0x32c, 0x0250e620); + cx25840_write4(client, 0x39c, 0x01FF0B00); + + cx25840_write4(client, 0x410, 0xffff0dbf); + cx25840_write4(client, 0x414, 0x00137d03); + cx25840_write4(client, 0x418, 0x01008080); + cx25840_write4(client, 0x41c, 0x00000000); + cx25840_write4(client, 0x420, 0x001c3e0f); + cx25840_write4(client, 0x42c, 0x42600000); + cx25840_write4(client, 0x430, 0x0000039b); + cx25840_write4(client, 0x438, 0x00000000); + + cx25840_write4(client, 0x440, 0xF8E3E824); + cx25840_write4(client, 0x444, 0x401040dc); + cx25840_write4(client, 0x448, 0xcd3f02a0); + cx25840_write4(client, 0x44c, 0x161f1000); + cx25840_write4(client, 0x450, 0x00000802); + + cx25840_write4(client, 0x91c, 0x01000000); + cx25840_write4(client, 0x8e0, 0x03063870); + cx25840_write4(client, 0x8d4, 0x7FFF0024); + cx25840_write4(client, 0x8d0, 0x00063073); + + cx25840_write4(client, 0x8c8, 0x00010000); + cx25840_write4(client, 0x8cc, 0x00080023); + + /* DIF BYPASS */ + cx25840_write4(client, 0x33c, 0x2a04c800); + } + + /* Reset the DIF */ + cx25840_write4(client, 0x398, 0); + } + if (!is_cx2388x(state) && !is_cx231xx(state)) { /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); @@ -1036,6 +1156,33 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_and_or(client, 0x102, ~0x2, 0); } } + + /* cx23885 / SVIDEO */ + if (is_cx2388x(state) && is_svideo) { +#define AFE_CTRL (0x104) +#define MODE_CTRL (0x400) + cx25840_and_or(client, 0x102, ~0x2, 0x2); + + val = cx25840_read4(client, MODE_CTRL); + val &= 0xFFFFF9FF; + + /* YC */ + val |= 0x00000200; + val &= ~0x2000; + cx25840_write4(client, MODE_CTRL, val); + + val = cx25840_read4(client, AFE_CTRL); + + /* Chroma in select */ + val |= 0x00001000; + val &= 0xfffffe7f; + /* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8). + * This sets them to use video rather than audio. + * Only one of the two will be in use. + */ + cx25840_write4(client, AFE_CTRL, val); + } else + cx25840_and_or(client, 0x102, ~0x2, 0); } state->vid_input = vid_input; @@ -1086,6 +1233,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x8d0, 0x1f063870); } + if (is_cx2388x(state)) { + /* HVR1850 */ + /* AUD_IO_CTRL - I2S Input, Parallel1*/ + /* - Channel 1 src - Parallel1 (Merlin out) */ + /* - Channel 2 src - Parallel2 (Merlin out) */ + /* - Channel 3 src - Parallel3 (Merlin AC97 out) */ + /* - I2S source and dir - Merlin, output */ + cx25840_write4(client, 0x124, 0x100); + + if (!is_dif) { + /* Stop microcontroller if we don't need it + * to avoid audio popping on svideo/composite use. + */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + } + } + return 0; } @@ -1134,7 +1298,10 @@ static int set_v4lstd(struct i2c_client *client) } cx25840_and_or(client, 0x400, ~0xf, fmt); cx25840_and_or(client, 0x403, ~0x3, pal_m); - cx25840_std_setup(client); + if (is_cx2388x(state)) + cx23885_std_setup(client); + else + cx25840_std_setup(client); if (!is_cx2583x(state)) input_change(client); return 0; @@ -1539,6 +1706,56 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +/* Query the current detected video format */ +static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + v4l2_std_id stds[] = { + /* 0000 */ V4L2_STD_UNKNOWN, + + /* 0001 */ V4L2_STD_NTSC_M, + /* 0010 */ V4L2_STD_NTSC_M_JP, + /* 0011 */ V4L2_STD_NTSC_443, + /* 0100 */ V4L2_STD_PAL, + /* 0101 */ V4L2_STD_PAL_M, + /* 0110 */ V4L2_STD_PAL_N, + /* 0111 */ V4L2_STD_PAL_Nc, + /* 1000 */ V4L2_STD_PAL_60, + + /* 1001 */ V4L2_STD_UNKNOWN, + /* 1010 */ V4L2_STD_UNKNOWN, + /* 1001 */ V4L2_STD_UNKNOWN, + /* 1010 */ V4L2_STD_UNKNOWN, + /* 1011 */ V4L2_STD_UNKNOWN, + /* 1110 */ V4L2_STD_UNKNOWN, + /* 1111 */ V4L2_STD_UNKNOWN + }; + + u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf; + *std = stds[ fmt ]; + + v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n", + fmt, (unsigned int)stds[ fmt ]); + + return 0; +} + +static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* A limited function that checks for signal status and returns + * the state. + */ + + /* Check for status of Horizontal lock (SRC lock isn't reliable) */ + if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0) + *status |= V4L2_IN_ST_NO_SIGNAL; + + return 0; +} + static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct cx25840_state *state = to_state(sd); @@ -1565,6 +1782,9 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd, struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (is_cx2388x(state)) + cx23885_std_setup(client); + return set_input(client, input, state->aud_input); } @@ -1574,6 +1794,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (is_cx2388x(state)) + cx23885_std_setup(client); return set_input(client, state->vid_input, input); } @@ -1786,6 +2008,3007 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, /* ----------------------------------------------------------------------- */ +#define DIF_PLL_FREQ_WORD (0x300) +#define DIF_BPF_COEFF01 (0x348) +#define DIF_BPF_COEFF23 (0x34c) +#define DIF_BPF_COEFF45 (0x350) +#define DIF_BPF_COEFF67 (0x354) +#define DIF_BPF_COEFF89 (0x358) +#define DIF_BPF_COEFF1011 (0x35c) +#define DIF_BPF_COEFF1213 (0x360) +#define DIF_BPF_COEFF1415 (0x364) +#define DIF_BPF_COEFF1617 (0x368) +#define DIF_BPF_COEFF1819 (0x36c) +#define DIF_BPF_COEFF2021 (0x370) +#define DIF_BPF_COEFF2223 (0x374) +#define DIF_BPF_COEFF2425 (0x378) +#define DIF_BPF_COEFF2627 (0x37c) +#define DIF_BPF_COEFF2829 (0x380) +#define DIF_BPF_COEFF3031 (0x384) +#define DIF_BPF_COEFF3233 (0x388) +#define DIF_BPF_COEFF3435 (0x38c) +#define DIF_BPF_COEFF36 (0x390) + +void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) +{ + u64 pll_freq; + u32 pll_freq_word; + + v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz); + + /* Assuming TV */ + /* Calculate the PLL frequency word based on the adjusted ifHz */ + pll_freq = div_u64((u64)ifHz * 268435456, 50000000); + pll_freq_word = (u32)pll_freq; + + cx25840_write4(client, DIF_PLL_FREQ_WORD, pll_freq_word); + + /* Round down to the nearest 100KHz */ + ifHz = (ifHz / 100000) * 100000; + + if (ifHz < 3000000) + ifHz = 3000000; + + if (ifHz > 16000000) + ifHz = 16000000; + + v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz); + + switch (ifHz) { + case 3000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0024); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001bfff8); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff50); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed8fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe34); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfebaffc7); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d031f); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04f0065d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07010688); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04c901d6); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f9d3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f342); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f337); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf64efb22); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105070f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0c460fce); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00220032); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00370026); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff91); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0efe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fdcc); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe0afedb); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440224); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0434060c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738074e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06090361); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99fb39); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef3b6); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21af2a5); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf573fa33); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034067d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bfb0fb9); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00200038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c004f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002fffdf); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff5cfeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dfd92); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7ffe03); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36010a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03410575); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x072607d2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x071804d5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134fcb7); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff451); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223f22e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4a7f94b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xff6405e8); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0bae0fa4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00000008); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0036); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0056006d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00670030); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffbdff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46fd8d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd25fd4f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35ffe0); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0224049f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9080e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x07ef0627); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9fe45); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f513); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250f1d2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3ecf869); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930552); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b5f0f8f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0001); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000f002c); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0054007d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0093007c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0024ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6fdbb); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd03fcca); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51feb9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00eb0392); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270802); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08880750); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x044dffdb); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf5f8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0f193); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf342f78f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc404b9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0b0e0f78); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff9); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0002001b); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0046007d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad00ba); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00870000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe1a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1bfc7e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fda4); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xffa5025c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x054507ad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08dd0847); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80172); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef6ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313f170); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2abf6bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6041f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0abc0f61); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff50006); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002f006c); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b200e3); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00dc007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9fea0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd6bfc71); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fcb1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe65010b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x042d0713); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ec0906); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020302); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff823); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7f16a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf228f5f5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2a0384); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a670f4a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9fff1); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010004d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a100f2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011a00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053ff44); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdedfca2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fbef); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd39ffae); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x02ea0638); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08b50987); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230483); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f960); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45bf180); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1b8f537); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb6102e7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x0a110f32); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffdd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00024); + cx25840_write4(client, DIF_BPF_COEFF89, 0x007c00e5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013a014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e6fff8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe98fd0f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fb67); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc32fe54); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x01880525); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x083909c7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x091505ee); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7fab3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52df1b4); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf15df484); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9b0249); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x09ba0f19); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 3900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffcf); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1fff6); + cx25840_write4(client, DIF_BPF_COEFF89, 0x004800be); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01390184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x016300ac); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff5efdb1); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb23); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb5cfd0d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x001703e4); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x077b09c4); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d2073c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251fc18); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61cf203); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf118f3dc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d801aa); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x09600eff); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffefff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffca); + cx25840_write4(client, DIF_BPF_COEFF89, 0x000b0082); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01170198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10152); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0030fe7b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb24); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfac3fbe9); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0683097f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a560867); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2fd89); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723f26f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0e8f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919010a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x09060ee5); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8ffca); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffa4); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffcd0036); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d70184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f601dc); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ffff60); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb6d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6efaf5); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd410103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x055708f9); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e0969); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543ff02); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842f2f5); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cef2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85e006b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x08aa0ecb); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050003); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff3ffd3); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaff8b); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ffe5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0080014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe023f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ba0050); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fbf8); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa62fa3b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9ff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04010836); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa90a3d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f007f); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf975f395); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0cbf231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ffcb); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x084c0eaf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000a); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0000ffe4); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff81); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff96); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x001c00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70271); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0254013b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fcbd); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa9ff9c5); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbfdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x028c073b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a750adf); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e101fa); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab8f44e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0ddf1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ff2b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x07ed0e94); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000efff8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff87); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff54); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffb5007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01860270); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c00210); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fdb2); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb22f997); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2fc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0102060f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a050b4c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902036e); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0af51e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf106f15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64efe8b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x078d0e77); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0019000e); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff9e); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff25); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff560000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112023b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f702c0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfec8); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbe5f9b3); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xff7004b9); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a0b81); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a0004d8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd65f603); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf144f104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aafdec); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x072b0e5a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00200022); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ffc1); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ff10); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff09ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x008601d7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f50340); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fff0); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcddfa19); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfde30343); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08790b7f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50631); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec7f6fc); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf198f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50dfd4e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x06c90e3d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00220030); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffed); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff87ff15); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed6ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffed014c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b90386); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110119); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfdfefac4); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6f92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc6701b7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07670b44); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0776); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x002df807); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf200f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477fcb1); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x06650e1e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0009); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f001b); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffbcff36); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec2feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff5600a5); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0248038d); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00232); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff39fbab); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4f87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb060020); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x062a0ad2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf908a3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0192f922); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf27df05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8fc14); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x06000e00); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 4900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0002); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00160037); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00510046); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff9ff6d); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed0fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefff0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01aa0356); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413032b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x007ffcc5); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cf812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9cefe87); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c90a2c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4309b4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f3fa4a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf30ef046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361fb7a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x059b0de0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000a002d); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00570067); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0037ffb5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfefffe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62ff3d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00ec02e3); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x043503f6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x01befe05); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa27f7ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8c6fcf8); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x034c0954); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0aa4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x044cfb7e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3b1f03f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2fae1); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x05340dc0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffd001e); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0051007b); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006e0006); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff48fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfe9a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x001d023e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130488); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02e6ff5b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1ef812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7f7fb7f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bc084e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430b72); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x059afcba); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf467f046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cfa4a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x04cd0da0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff00009); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00980056); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffa5feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe15); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff4b0170); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b004d7); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03e800b9); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc48f87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf768fa23); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022071f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90c1b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x06dafdfd); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf52df05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef9b5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x04640d7f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6fff3); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00250072); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00af009c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x000cff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13fdb8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe870089); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104e1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04b8020f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd98f92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf71df8f0); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe8805ce); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0c9c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0808ff44); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf603f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af922); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x03fb0d5e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe0); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00050056); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b000d1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0071ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53fd8c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfddfff99); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104a3); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x054a034d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff01fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf717f7ed); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf50461); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50cf4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0921008d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf6e7f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff891); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x03920d3b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffffff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffd1); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5002f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009c00ed); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00cb0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfebafd94); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd61feb0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d0422); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05970464); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0074fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf759f721); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb7502de); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000d21); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a2201d4); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7d9f104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf804); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x03280d19); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fffa); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3ffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc90002); + cx25840_write4(client, DIF_BPF_COEFF89, 0x007500ef); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x010e007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3dfdcf); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd16fddd); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440365); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x059b0548); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3fc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7dff691); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0f014d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020d23); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0318); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8d7f15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f779); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x02bd0cf6); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060001); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffecffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffd4); + cx25840_write4(client, DIF_BPF_COEFF89, 0x004000d5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013600f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd3fe39); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd04fd31); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff360277); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x055605ef); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x033efdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8a5f642); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbffb6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10cfb); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50456); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9dff1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f6f2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x02520cd2); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080009); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff8ffd2); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffac); + cx25840_write4(client, DIF_BPF_COEFF89, 0x000200a3); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013c014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x006dfec9); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2bfcb7); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe350165); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04cb0651); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477ff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9a5f635); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1fe20); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0ca8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c81058b); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfaf0f231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f66d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x01e60cae); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 5900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0009000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0005ffe1); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacff90); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5005f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01210184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fcff72); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd8afc77); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51003f); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04020669); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfad7f66b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8fc93); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430c2b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d06b5); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfc08f2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af5ec); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x017b0c89); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0012fff5); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff8e000f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e80198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750028); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe18fc75); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99ff15); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03050636); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0656027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc32f6e2); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614fb17); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20b87); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d7707d2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfd26f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf56f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x010f0c64); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001c000b); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff84); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ffbe); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00960184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd00da); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeccfcb2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fdf9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x01e005bc); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e703e4); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfdabf798); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f9b3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510abd); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf08df); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfe48f3dc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f4f6); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x00a20c3e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021001f); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff97); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff74); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0034014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa0179); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff97fd2a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fcfa); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00a304fe); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310525); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xff37f886); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf86e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c709d0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de209db); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xff6df484); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf481); + cx25840_write4(client, DIF_BPF_COEFF3435, 0x00360c18); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe000a); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021002f); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ffb8); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff50ff3b); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffcc00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fa01fa); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0069fdd4); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fc26); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff5d0407); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07310638); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x00c9f9a8); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55cf74e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff3908c3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de20ac3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0093f537); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefcbf410); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xffca0bf2); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb0003); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001c0037); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002fffe2); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff66ff17); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff6a007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01cd0251); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0134fea5); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fb8b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe2002e0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06e70713); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0255faf5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf599f658); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0799); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dbf0b96); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x01b8f5f5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefd5f3a3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xff5e0bca); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00120037); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00460010); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff8eff0f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff180000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01750276); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01e8ff8d); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fb31); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcfb0198); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x065607ad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x03cefc64); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf614f592); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0656); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d770c52); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x02daf6bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xefeaf33b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfef10ba3); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff5); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0005002f); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0054003c); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffc5ff22); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedfff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00fc0267); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0276007e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb1c); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbfe003e); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05830802); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0529fdec); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6c8f4fe); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd04ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d0d0cf6); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x03f8f78f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf00af2d7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe850b7b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff80020); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00560060); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0002ff4e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec4ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x006d0225); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02d50166); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb4e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb35fee1); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0477080e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x065bff82); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7b1f4a0); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610397); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c810d80); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0510f869); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf033f278); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfe1a0b52); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffaffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffec000c); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0078); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0040ff8e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecafeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffd301b6); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fc0235); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fbc5); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaaafd90); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x033e07d2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x075b011b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf8cbf47a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f0224); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0bd50def); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0621f94b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf067f21e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfdae0b29); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 6900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe3fff6); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0037007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0075ffdc); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef2fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff3d0122); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02ea02dd); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fc79); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa65fc5d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x01e3074e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x082102ad); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa0ff48c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe00a9); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b0a0e43); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0729fa33); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0a5f1c9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfd430b00); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0001fff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe2); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001b0076); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009c002d); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff35fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfeba0076); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x029f0352); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfd60); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa69fb53); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x00740688); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08a7042d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfb75f4d6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600ff2d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a220e7a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0827fb22); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf0edf17a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfcd80ad6); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff9); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffd2); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb005e); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b0007a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8ffe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe53ffc1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0221038c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fe6e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfab6fa80); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff010587); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e90590); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfcf5f556); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfdb3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x09210e95); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0919fc15); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf13ff12f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc6e0aab); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070000); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe6ffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0039); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00af00b8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfff4feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe13ff10); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01790388); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311ff92); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb48f9ed); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd980453); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08e306cd); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe88f60a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fc40); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x08080e93); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x09fdfd0c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf19af0ea); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfc050a81); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080008); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff0ffc9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1000d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009800e2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x005bff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe00fe74); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00b50345); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000bc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc18f9a1); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc4802f9); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x089807dc); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0022f6f0); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fada); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x06da0e74); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ad3fe06); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf1fef0ab); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb9c0a55); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffdffd0); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffdf); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006e00f2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00b8ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe1bfdf8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffe302c8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x041301dc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd1af99e); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb1e0183); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x080908b5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x01bcf801); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf985); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x059a0e38); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b99ff03); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf26cf071); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfb330a2a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00070011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000affdf); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffa9ffb5); + cx25840_write4(client, DIF_BPF_COEFF89, 0x003700e6); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01010000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe62fda8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff140219); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x043502e1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe42f9e6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa270000); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x073a0953); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x034cf939); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a4f845); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x044c0de1); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c4f0000); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf2e2f03c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfacc09fe); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00040012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0016fff3); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffafff95); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff900c0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0130007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfecefd89); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe560146); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x041303bc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff81fa76); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf96cfe7d); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x063209b1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x04c9fa93); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdf71e); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x02f30d6e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cf200fd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf361f00e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa6509d1); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00010010); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e0008); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ff84); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffbc0084); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013e00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff56fd9f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdb8005c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00460); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00c7fb45); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8f4fd07); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04fa09ce); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x062afc07); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407f614); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x01920ce0); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d8301fa); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf3e8efe5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xfa0009a4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd000b); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001d); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff870039); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x012a014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffedfde7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd47ff6b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x031104c6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0202fc4c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8c6fbad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x039909a7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0767fd8e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482f52b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x002d0c39); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e0002f4); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf477efc2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf99b0977); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 7900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa0004); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0020002d); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff91); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff61ffe8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f70184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0086fe5c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0bfe85); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104e5); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0323fd7d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8e2fa79); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x021d093f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0879ff22); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bf465); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfec70b79); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e6803eb); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf50defa5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf937094a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffd); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00190036); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001bffaf); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4fff99); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00aa0198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0112fef3); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd09fdb9); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04be); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x041bfecc); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf947f978); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x00900897); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x095a00b9); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f3c5); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfd650aa3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ebc04de); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf5aaef8e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf8d5091c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff7fff6); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000e0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ffd7); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff52ff56); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x004b0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0186ffa1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd40fd16); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440452); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04de0029); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9f2f8b2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfefe07b5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a05024d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef34d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfc0a09b8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0efa05cd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf64eef7d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf87308ed); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00000031); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0005); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff6aff27); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffe4014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01d70057); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdacfca6); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3603a7); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05610184); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfadbf82e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd74069f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a7503d6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff2ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfab808b9); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f2306b5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf6f9ef72); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf81308bf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff30022); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00560032); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff95ff10); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff8000f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01fe0106); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe46fc71); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3502c7); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x059e02ce); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbf9f7f2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfbff055b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aa9054c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f2db); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf97507aa); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f350797); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf7a9ef6d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7b40890); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe8000f); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00540058); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffcdff14); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff29007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f6019e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff01fc7c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5101bf); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x059203f6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfd41f7fe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfaa903f3); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a9e06a9); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf2e2); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf842068b); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f320871); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf85eef6e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf7560860); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002fff2); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1fff9); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00460073); + cx25840_write4(client, DIF_BPF_COEFF89, 0x000bff34); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee90000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01c10215); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffd0fcc5); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99009d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x053d04f1); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfea5f853); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf97d0270); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a5607e4); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef314); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf723055f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0f180943); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf919ef75); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6fa0830); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff8); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffe4); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002f007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0048ff6b); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec7ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0163025f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00a2fd47); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff73); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04a405b2); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0017f8ed); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf88500dc); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x09d208f9); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff370); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf61c0429); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ee80a0b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xf9d8ef82); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf6a00800); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007ffff); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe1ffd4); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010007a); + cx25840_write4(client, DIF_BPF_COEFF89, 0x007cffb2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec6ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00e60277); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0168fdf9); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fe50); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x03ce0631); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0188f9c8); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7c7ff43); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x091509e3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f3f6); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf52d02ea); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0ea30ac9); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfa9bef95); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf64607d0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00090007); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe9ffca); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff00065); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a10003); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfee6feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0053025b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0213fed0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3fd46); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02c70668); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x02eafadb); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf74bfdae); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08230a9c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f4a3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf45b01a6); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0e480b7c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfb61efae); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf5ef079f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 8900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000d); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff5ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10043); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b20053); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff24fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffb9020c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0295ffbb); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fc64); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x019b0654); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x042dfc1c); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf714fc2a); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07020b21); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f575); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3a7005e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0dd80c24); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfc2aefcd); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf599076e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0002ffcf); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffba0018); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00ad009a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff79fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff260192); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e500ab); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fbb6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x005b05f7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545fd81); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf723fabf); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b80b70); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f669); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf313ff15); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d550cbf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6eff2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544073d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00030012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000fffdd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffea); + cx25840_write4(client, DIF_BPF_COEFF89, 0x009300cf); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdcfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea600f7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fd0190); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fb46); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff150554); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0627fefd); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf778f978); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x044d0b87); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f77d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a0fdcf); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbe0d4e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc4f01d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2070b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00000010); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001afff0); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaaffbf); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006700ed); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe460047); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02db0258); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb1b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddc0473); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c90082); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf811f85e); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c90b66); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff8ad); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf250fc8d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c140dcf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe93f04d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a106d9); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc000c); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00200006); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ff9c); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002f00ef); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a4ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0dff92); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x028102f7); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb37); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbf035e); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07260202); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e8f778); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x01340b0d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f9f4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf223fb51); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b590e42); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xff64f083); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf45206a7); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90005); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0022001a); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ff86); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff000d7); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01fee5); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f60362); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb99); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbcc0222); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07380370); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f7f6cc); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff990a7e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902fb50); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21afa1f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8d0ea6); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0034f0bf); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4050675); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fffe); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001e002b); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff81); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffb400a5); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe24fe50); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01460390); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfc3a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb1000ce); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x070104bf); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb37f65f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe0009bc); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00fcbb); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf235f8f8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b20efc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0105f101); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3ba0642); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff7); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00150036); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff8c); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff810061); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013d007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe71fddf); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x007c0380); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fd13); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa94ff70); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x068005e2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9bf633); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc7308ca); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5fe30); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf274f7e0); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c90f43); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d4f147); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371060f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fff1); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00090038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ffa7); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5e0012); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013200f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee3fd9b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaa0331); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fe15); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa60fe18); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bd06d1); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1bf64a); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafa07ae); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7effab); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d5f6d7); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d30f7a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a3f194); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf32905dc); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffb0032); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003fffcd); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effc1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6efd8a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfedd02aa); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0ff34); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa74fcd7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bf0781); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaaf6a3); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99e066b); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf90128); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf359f5e1); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d20fa2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0370f1e5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e405a8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 9900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffef0024); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0051fffa); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff54ff77); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00be0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0006fdad); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe2701f3); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413005e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad1fbba); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x039007ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x013bf73d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868050a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c4302a1); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fdf4fe); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c70fba); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x043bf23c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a10575); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003fff1); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe50011); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00570027); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff70ff3c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00620198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x009efe01); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95011a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350183); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb71fad0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x023c0812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c3f811); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75e0390); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5c0411); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c1f432); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b30fc1); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0503f297); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2610541); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0006fff7); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdffffc); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00510050); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff9dff18); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffc0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0128fe80); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32002e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130292); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4dfa21); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d107ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0435f91c); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6850205); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c430573); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a1f37d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x03990fba); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c7f2f8); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222050d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffe); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdfffe7); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f006e); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffd6ff0f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0197ff1f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd05ff3e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0037c); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd59f9b7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5d0781); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0585fa56); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4006f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf906c4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69df2e0); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x02790fa2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0688f35d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e604d8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00090005); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4ffd6); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025007e); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0014ff20); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3c00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e1ffd0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd12fe5c); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110433); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88f996); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf106d1); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aafbb7); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57efed8); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e07ff); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b0f25e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x01560f7a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0745f3c7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1ac04a4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008000c); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffedffcb); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005007d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0050ff4c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ff0086); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd58fd97); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024104ad); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xffcaf9c0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc9905e2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x079afd35); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf555fd46); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad50920); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d9f1f6); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x00310f43); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fdf435); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174046f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xfffffffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050011); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffaffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5006b); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0082ff8c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f00130); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd2fcfc); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d04e3); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x010efa32); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb6404bf); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x084efec5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569fbc2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000a23); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa15f1ab); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0b0efc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b0f4a7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13f043a); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00020012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0007ffcd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9004c); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a4ffd9); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b401c1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe76fc97); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404d2); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0245fae8); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5f0370); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1005f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bcfa52); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x09020b04); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb60f17b); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde70ea6); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x095df51e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10c0405); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0014ffdb); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40023); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2002a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedbff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150022d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff38fc6f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36047b); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x035efbda); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9940202); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08ee01f5); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf649f8fe); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e10bc2); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb6f169); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc60e42); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a04f599); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0db03d0); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffb000d); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001dffed); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaafff5); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00aa0077); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00ce026b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x000afc85); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3503e3); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x044cfcfb); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90c0082); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5037f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf710f7cc); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0c59); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe16f173); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaa0dcf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa5f617); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0ad039b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 10900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff90006); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00210003); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffacffc8); + cx25840_write4(client, DIF_BPF_COEFF89, 0x008e00b6); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff63fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x003a0275); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00dafcda); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd510313); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0501fe40); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cbfefd); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x087604f0); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80af6c2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430cc8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7af19a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa940d4e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3ff699); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0810365); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8ffff); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00210018); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffa3); + cx25840_write4(client, DIF_BPF_COEFF89, 0x006000e1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc4fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0024b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x019afd66); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc990216); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0575ff99); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4fd81); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d40640); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf932f5e6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20d0d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x00dff1de); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf9860cbf); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd1f71e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058032f); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff8); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001b0029); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd1ff8a); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002600f2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x002cfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0f01f0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x023bfe20); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc1700fa); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a200f7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf927fc1c); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f40765); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa82f53b); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x02510d27); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0243f23d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf8810c24); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5cf7a7); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf03102fa); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00110035); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0ff81); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffe700e7); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x008ffeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94016d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b0fefb); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3ffd1); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05850249); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c1fadb); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x05de0858); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf2f4c4); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c70d17); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a0f2b8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf7870b7c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdff833); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00d02c4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffdffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00040038); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0010ff88); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffac00c2); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e2ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe3900cb); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f1ffe9); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3feaa); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05210381); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9cf9c8); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x04990912); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7af484); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff390cdb); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f4f34d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69a0ac9); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5af8c1); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefec028e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0000ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff60033); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002fff9f); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7b0087); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011eff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe080018); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f900d8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17fd96); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x04790490); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbadf8ed); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x032f098e); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff10f47d); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaf0c75); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x063cf3fc); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5ba0a0b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dccf952); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcd0258); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004fff1); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffea0026); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0046ffc3); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5a003c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04ff63); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c801b8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fca6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397056a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcecf853); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x01ad09c9); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x00acf4ad); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2e0be7); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0773f4c2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e90943); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35f9e6); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb10221); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff6); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe20014); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0054ffee); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4effeb); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2efebb); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260027a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fbe6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02870605); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4af7fe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x001d09c1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0243f515); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabd0b32); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0897f59e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4280871); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e95fa7c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef9701eb); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffd); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdeffff); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0056001d); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff57ff9c); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011300f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe82fe2e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01ca0310); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fb62); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155065a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xffbaf7f2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8c0977); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x03cef5b2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf9610a58); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a5f68f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf3790797); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eebfb14); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef8001b5); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080004); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe0ffe9); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004c0047); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff75ff58); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef9fdc8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111036f); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb21); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x00120665); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x012df82e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd0708ec); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542f682); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81f095c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9af792); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2db06b5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f38fbad); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6c017e); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 11900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000b); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe7ffd8); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00370068); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffa4ff28); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00790184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87fd91); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00430392); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb26); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfece0626); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294f8b2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb990825); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0698f77f); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fe0842); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b73f8a7); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf25105cd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7bfc48); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5a0148); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00050010); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff2ffcc); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001b007b); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffdfff10); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00140198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0020fd8e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff710375); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb73); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9a059f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e0f978); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4e0726); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c8f8a7); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600070c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2ff9c9); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1db04de); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4fce5); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4b0111); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00010012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffffffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffb007e); + cx25840_write4(client, DIF_BPF_COEFF89, 0x001dff14); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffad0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b7fdbe); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9031b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fc01); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc8504d6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0504fa79); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf93005f6); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08caf9f2); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52b05c0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccbfaf9); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf17903eb); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3fd83); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3f00db); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffe0011); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000cffcc); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdb0071); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0058ff32); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4f014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x013cfe1f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfb028a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fcc9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9d03d6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f4fbad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848049d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0999fb5b); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf4820461); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d46fc32); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12d02f4); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x1007fe21); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3600a4); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0017ffd9); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc10055); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0088ff68); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff0400f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a6fea7); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd7501cc); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fdc0); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaef02a8); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a7fd07); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79d0326); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a31fcda); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf40702f3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9ffd72); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f601fa); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x1021fec0); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2f006d); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80007); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001fffeb); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaf002d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a8ffb0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e9ff4c); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd2000ee); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fed8); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82015c); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0715fe7d); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7340198); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8dfe69); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bd017c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd5feb8); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d500fd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x1031ff60); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2b0037); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff70000); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00220000); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffa90000); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b30000); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec20000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x02000000); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd030000); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04350000); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa5e0000); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x073b0000); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7110000); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0aac0000); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3a40000); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0de70000); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0c90000); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x10360000); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef290000); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff8fff9); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001f0015); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffafffd3); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a80050); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfed3ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e900b4); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd20ff12); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x04130128); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa82fea4); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x07150183); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf734fe68); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a8d0197); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf3bdfe84); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0dd50148); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0d5ff03); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x103100a0); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2bffc9); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffafff2); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00170027); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc1ffab); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00880098); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff04ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01a60159); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd75fe34); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b00240); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfaeffd58); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06a702f9); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf79dfcda); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0a310326); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf407fd0d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d9f028e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf0f6fe06); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x10210140); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef2fff93); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffeffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000c0034); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffdbff8f); + cx25840_write4(client, DIF_BPF_COEFF89, 0x005800ce); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff4ffeb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x013c01e1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdfbfd76); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03110337); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb9dfc2a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05f40453); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf848fb63); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x099904a5); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf482fb9f); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0d4603ce); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf12dfd0c); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x100701df); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef36ff5c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 12900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0001ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffff0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfffbff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0x001d00ec); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffadfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00b70242); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfea9fce5); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024103ff); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc85fb2a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05040587); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf930fa0a); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x08ca060e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf52bfa40); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0ccb0507); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf179fc15); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fe3027d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef3fff25); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0005fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff20034); + cx25840_write4(client, DIF_BPF_COEFF67, 0x001bff85); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffdf00f0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0014fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00200272); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff71fc8b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d048d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd9afa61); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x03e00688); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfa4ef8da); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x07c80759); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf600f8f4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0c2f0637); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf1dbfb22); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0fb4031b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef4bfeef); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007fff5); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe70028); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0037ff98); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffa400d8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0079fe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff87026f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0043fc6e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x004404da); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfecef9da); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0294074e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb99f7db); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x06980881); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf6fef7be); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0b730759); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf251fa33); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f7b03b8); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef5afeb8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0000); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fffc); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe00017); + cx25840_write4(client, DIF_BPF_COEFF67, 0x004cffb9); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7500a8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00d1feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfef90238); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0111fc91); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604df); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0012f99b); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x012d07d2); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfd07f714); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0542097e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf81ff6a4); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x0a9a086e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf2dbf94b); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0f380453); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef6cfe82); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080003); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffde0001); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0056ffe3); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff570064); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0113ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe8201d2); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01cafcf0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35049e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0155f9a6); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xffba080e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe8cf689); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x03ce0a4e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xf961f5a8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x09a50971); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf379f869); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0eeb04ec); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef80fe4b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0007000a); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe2ffec); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00540012); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e0015); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0137ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2e0145); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0260fd86); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51041a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0287f9fb); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfe4a0802); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x001df63f); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02430aeb); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfabdf4ce); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x08970a62); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf428f78f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e950584); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xef97fe15); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0004000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffeaffda); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0046003d); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5affc4); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013b0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe04009d); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02c8fe48); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99035a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0397fa96); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfcec07ad); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x01adf637); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x00ac0b53); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfc2ef419); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x07730b3e); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf4e9f6bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0e35061a); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefb1fddf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00000012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfff6ffcd); + cx25840_write4(client, DIF_BPF_COEFF67, 0x002f0061); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7bff79); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x011e007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe08ffe8); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f9ff28); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17026a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0479fb70); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfbad0713); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x032ff672); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff100b83); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xfdaff38b); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x063c0c04); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf5baf5f5); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0dcc06ae); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefcdfda8); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffd0012); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0004ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00100078); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffacff3e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00e200f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe39ff35); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02f10017); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd30156); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0521fc7f); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa9c0638); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0499f6ee); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfd7a0b7c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0xff39f325); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x04f40cb3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf69af537); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0d5a073f); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xefecfd72); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffa000e); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0011ffcb); + cx25840_write4(client, DIF_BPF_COEFF67, 0xfff0007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffe7ff19); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x008f014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe94fe93); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02b00105); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfbd3002f); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x0585fdb7); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf9c10525); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x05def7a8); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfbf20b3c); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x00c7f2e9); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x03a00d48); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf787f484); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0cdf07cd); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf00dfd3c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 13900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010000); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80008); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001bffd7); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffd10076); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0026ff0e); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x002c0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff0ffe10); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x023b01e0); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc17ff06); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05a2ff09); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf92703e4); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06f4f89b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfa820ac5); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0251f2d9); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x02430dc3); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf881f3dc); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0c5c0859); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf031fd06); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80001); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021ffe8); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffba005d); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0060ff1f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffc40198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xffa0fdb5); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x019a029a); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99fdea); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x05750067); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8d4027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x07d4f9c0); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf9320a1a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d2f2f3); + cx25840_write4(client, DIF_BPF_COEFF2829, 0x00df0e22); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xf986f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0bd108e2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf058fcd1); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffa); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0021fffd); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0038); + cx25840_write4(client, DIF_BPF_COEFF89, 0x008eff4a); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff630184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x003afd8b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x00da0326); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd51fced); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x050101c0); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf8cb0103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x0876fb10); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf80a093e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0543f338); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xff7a0e66); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfa94f2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0b3f0967); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf081fc9b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffbfff3); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001d0013); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa000b); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00aaff89); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff13014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00cefd95); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x000a037b); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe35fc1d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x044c0305); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf90cff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08d5fc81); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf7100834); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069ff3a7); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfe160e8d); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfbaaf231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0aa509e9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0adfc65); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffffffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00140025); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb4ffdd); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00b2ffd6); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfedb00f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x0150fdd3); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xff380391); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff36fb85); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x035e0426); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xf994fdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08eefe0b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf6490702); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1f43e); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfcb60e97); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfcc6f1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x0a040a67); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf0dbfc30); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0002ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00070033); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9ffb4); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00a40027); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfec3007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01b4fe3f); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe760369); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0044fb2e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x02450518); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfa5ffc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x08c1ffa1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5bc05ae); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0902f4fc); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfb600e85); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xfde7f15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x095d0ae2); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf10cfbfb); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0005ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffa0038); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5ff95); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00820074); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfecc0000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01f0fed0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfdd20304); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014dfb1d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x010e05ce); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfb64fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x084e013b); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf569043e); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a00f5dd); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xfa150e55); + cx25840_write4(client, DIF_BPF_COEFF3031, 0xff0bf104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x08b00b59); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf13ffbc6); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0008fff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffed0035); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0005ff83); + cx25840_write4(client, DIF_BPF_COEFF89, 0x005000b4); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfef6ff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01ffff7a); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd580269); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0241fb53); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xffca0640); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfc99fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x079a02cb); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf55502ba); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad5f6e0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf8d90e0a); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0031f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x07fd0bcb); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf174fb91); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffffffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0009fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe4002a); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0025ff82); + cx25840_write4(client, DIF_BPF_COEFF89, 0x001400e0); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff3cff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01e10030); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd1201a4); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0311fbcd); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfe88066a); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xfdf1f92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x06aa0449); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf57e0128); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7ef801); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf7b00da2); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0156f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x07450c39); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1acfb5c); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00080002); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0019); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003fff92); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffd600f1); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff96feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x019700e1); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd0500c2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b0fc84); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfd590649); + cx25840_write4(client, DIF_BPF_COEFF2021, 0xff5df87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x058505aa); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf5e4ff91); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9f93c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf69d0d20); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0279f05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x06880ca3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf1e6fb28); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 14900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x00060009); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffdf0004); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0051ffb0); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff9d00e8); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xfffcfe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x01280180); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd32ffd2); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413fd6e); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfc4d05df); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x00d1f812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x043506e4); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf685fdfb); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fa8d); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf5a10c83); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0399f046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x05c70d08); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf222faf3); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffe5ffef); + cx25840_write4(client, DIF_BPF_COEFF67, 0x0057ffd9); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff7000c4); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0062fe68); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x009e01ff); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfd95fee6); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0435fe7d); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb710530); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x023cf7ee); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x02c307ef); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf75efc70); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c5cfbef); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf4c10bce); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x04b3f03f); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x05030d69); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf261fabf); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15100000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0000fffd); + cx25840_write4(client, DIF_BPF_COEFF23, 0xffff0012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xffefffdc); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00510006); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff540089); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00befe7c); + cx25840_write4(client, DIF_BPF_COEFF1213, 0x00060253); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfe27fe0d); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x0413ffa2); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfad10446); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0390f812); + cx25840_write4(client, DIF_BPF_COEFF2223, 0x013b08c3); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf868faf6); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0c43fd5f); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3fd0b02); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x05c7f046); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x043b0dc4); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2a1fa8b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15200000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001fffe); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffc0012); + cx25840_write4(client, DIF_BPF_COEFF45, 0xfffbffce); + cx25840_write4(client, DIF_BPF_COEFF67, 0x003f0033); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff4e003f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0106feb6); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff6e0276); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xfeddfd56); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x03b000cc); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa740329); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x04bff87f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xffaa095d); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xf99ef995); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0bf9fed8); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf3590a1f); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x06d2f05e); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x03700e1b); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf2e4fa58); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15300000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x0001ffff); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9000f); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0009ffc8); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00250059); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff5effee); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0132ff10); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfee30265); + cx25840_write4(client, DIF_BPF_COEFF1415, 0xffaafccf); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x031101eb); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa6001e8); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x05bdf92f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfe1b09b6); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfafaf852); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0b7e0055); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2d50929); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x07d3f086); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x02a30e6c); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf329fa24); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15400000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00010001); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80009); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0015ffca); + cx25840_write4(client, DIF_BPF_COEFF67, 0x00050074); + cx25840_write4(client, DIF_BPF_COEFF89, 0xff81ff9f); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x013dff82); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe710221); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x007cfc80); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x024102ed); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfa940090); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0680fa1e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfc9b09cd); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfc73f736); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0ad501d0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2740820); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x08c9f0bd); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x01d40eb9); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf371f9f1); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15500000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000002); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff80002); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001effd5); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffe5007f); + cx25840_write4(client, DIF_BPF_COEFF89, 0xffb4ff5b); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x01280000); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe2401b0); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0146fc70); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x014d03c6); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfb10ff32); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0701fb41); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xfb3709a1); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xfe00f644); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x0a000345); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2350708); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x09b2f104); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x01050eff); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf3baf9be); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15600000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfff9fffb); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0022ffe6); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffc9007a); + cx25840_write4(client, DIF_BPF_COEFF89, 0xfff0ff29); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00f2007e); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe01011b); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x01f6fc9e); + cx25840_write4(client, DIF_BPF_COEFF1617, 0x00440467); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfbccfdde); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0738fc90); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf9f70934); + cx25840_write4(client, DIF_BPF_COEFF2425, 0xff99f582); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x090204b0); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf21a05e1); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0a8df15a); + cx25840_write4(client, DIF_BPF_COEFF3233, 0x00340f41); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf405f98b); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15700000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0xfffcfff4); + cx25840_write4(client, DIF_BPF_COEFF45, 0x0020fffa); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffb40064); + cx25840_write4(client, DIF_BPF_COEFF89, 0x002fff11); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x00a400f0); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe0d006e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x0281fd09); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xff3604c9); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfcbffca2); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0726fdfe); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf8e80888); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x0134f4f3); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x07e1060c); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf22304af); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0b59f1be); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xff640f7d); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf452f959); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15800000: + cx25840_write4(client, DIF_BPF_COEFF01, 0x00000003); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0000fff0); + cx25840_write4(client, DIF_BPF_COEFF45, 0x001a0010); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffaa0041); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0067ff13); + cx25840_write4(client, DIF_BPF_COEFF1011, 0x0043014a); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfe46ffb9); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02dbfda8); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfe3504e5); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xfddcfb8d); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06c9ff7e); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf81107a2); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x02c9f49a); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x069f0753); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2500373); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0c14f231); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfe930fb3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4a1f927); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 15900000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0002); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0003ffee); + cx25840_write4(client, DIF_BPF_COEFF45, 0x000f0023); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffac0016); + cx25840_write4(client, DIF_BPF_COEFF89, 0x0093ff31); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xffdc0184); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xfea6ff09); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02fdfe70); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfd5104ba); + cx25840_write4(client, DIF_BPF_COEFF1819, 0xff15faac); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x06270103); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7780688); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x044df479); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x05430883); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf2a00231); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0cbef2b2); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfdc40fe3); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf4f2f8f5); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + + case 16000000: + cx25840_write4(client, DIF_BPF_COEFF01, 0xffff0001); + cx25840_write4(client, DIF_BPF_COEFF23, 0x0006ffef); + cx25840_write4(client, DIF_BPF_COEFF45, 0x00020031); + cx25840_write4(client, DIF_BPF_COEFF67, 0xffbaffe8); + cx25840_write4(client, DIF_BPF_COEFF89, 0x00adff66); + cx25840_write4(client, DIF_BPF_COEFF1011, 0xff790198); + cx25840_write4(client, DIF_BPF_COEFF1213, 0xff26fe6e); + cx25840_write4(client, DIF_BPF_COEFF1415, 0x02e5ff55); + cx25840_write4(client, DIF_BPF_COEFF1617, 0xfc99044a); + cx25840_write4(client, DIF_BPF_COEFF1819, 0x005bfa09); + cx25840_write4(client, DIF_BPF_COEFF2021, 0x0545027f); + cx25840_write4(client, DIF_BPF_COEFF2223, 0xf7230541); + cx25840_write4(client, DIF_BPF_COEFF2425, 0x05b8f490); + cx25840_write4(client, DIF_BPF_COEFF2627, 0x03d20997); + cx25840_write4(client, DIF_BPF_COEFF2829, 0xf31300eb); + cx25840_write4(client, DIF_BPF_COEFF3031, 0x0d55f341); + cx25840_write4(client, DIF_BPF_COEFF3233, 0xfcf6100e); + cx25840_write4(client, DIF_BPF_COEFF3435, 0xf544f8c3); + cx25840_write4(client, DIF_BPF_COEFF36, 0x110d0000); + break; + } +} + +static void cx23885_std_setup(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + v4l2_std_id std = state->std; + u32 ifHz; + + cx25840_write4(client, 0x478, 0x6628021F); + cx25840_write4(client, 0x400, 0x0); + cx25840_write4(client, 0x4b4, 0x20524030); + cx25840_write4(client, 0x47c, 0x010a8263); + + if (std & V4L2_STD_NTSC) { + v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC", + __func__); + + /* Horiz / vert timing */ + cx25840_write4(client, 0x428, 0x1e1e601a); + cx25840_write4(client, 0x424, 0x5b2d007a); + + /* DIF NTSC */ + cx25840_write4(client, 0x304, 0x6503bc0c); + cx25840_write4(client, 0x308, 0xbd038c85); + cx25840_write4(client, 0x30c, 0x1db4640a); + cx25840_write4(client, 0x310, 0x00008800); + cx25840_write4(client, 0x314, 0x44400400); + cx25840_write4(client, 0x32c, 0x0c800800); + cx25840_write4(client, 0x330, 0x27000100); + cx25840_write4(client, 0x334, 0x1f296e1f); + cx25840_write4(client, 0x338, 0x009f50c1); + cx25840_write4(client, 0x340, 0x1befbf06); + cx25840_write4(client, 0x344, 0x000035e8); + + /* DIF I/F */ + ifHz = 5400000; + + } else { + v4l_dbg(1, cx25840_debug, client, "%s() Selecting PAL-BG", + __func__); + + /* Horiz / vert timing */ + cx25840_write4(client, 0x428, 0x28244024); + cx25840_write4(client, 0x424, 0x5d2d0084); + + /* DIF */ + cx25840_write4(client, 0x304, 0x6503bc0c); + cx25840_write4(client, 0x308, 0xbd038c85); + cx25840_write4(client, 0x30c, 0x1db4640a); + cx25840_write4(client, 0x310, 0x00008800); + cx25840_write4(client, 0x314, 0x44400600); + cx25840_write4(client, 0x32c, 0x0c800800); + cx25840_write4(client, 0x330, 0x27000100); + cx25840_write4(client, 0x334, 0x213530ec); + cx25840_write4(client, 0x338, 0x00a65ba8); + cx25840_write4(client, 0x340, 0x1befbf06); + cx25840_write4(client, 0x344, 0x000035e8); + + /* DIF I/F */ + ifHz = 6000000; + } + + cx23885_dif_setup(client, ifHz); + + /* Explicitly ensure the inputs are reconfigured after + * a standard change. + */ + set_input(client, state->vid_input, state->aud_input); +} + +/* ----------------------------------------------------------------------- */ + static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { .s_ctrl = cx25840_s_ctrl, }; @@ -1801,6 +5024,7 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = { .queryctrl = v4l2_subdev_queryctrl, .querymenu = v4l2_subdev_querymenu, .s_std = cx25840_s_std, + .g_std = cx25840_g_std, .reset = cx25840_reset, .load_fw = cx25840_load_fw, .s_io_pin_config = common_s_io_pin_config, @@ -1828,6 +5052,7 @@ static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_routing = cx25840_s_video_routing, .s_mbus_fmt = cx25840_s_mbus_fmt, .s_stream = cx25840_s_stream, + .g_input_status = cx25840_g_input_status, }; static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = { diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 5c42abdf422f..3598dc087b08 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -70,11 +70,6 @@ config VIDEO_CX88_DVB To compile this driver as a module, choose M here: the module will be called cx88-dvb. -config VIDEO_CX88_MPEG - tristate - depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD - default y - config VIDEO_CX88_VP3054 tristate "VP-3054 Secondary I2C Bus Support" default m @@ -84,3 +79,8 @@ config VIDEO_CX88_VP3054 Conexant 2388x chip and the MT352 demodulator, which also require support for the VP-3054 Secondary I2C bus, such at DNTV Live! DVB-T Pro. + +config VIDEO_CX88_MPEG + tristate + depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD + default y diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 68d1240f493c..04bf6627d362 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -96,7 +96,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t; static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; +static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 0d719faafd8a..62c7ad050f9b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1306,7 +1306,7 @@ static const struct cx88_board cx88_boards[] = { }, [CX88_BOARD_WINFAST_DTV2000H_J] = { .name = "WinFast DTV2000 H rev. J", - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -1643,6 +1643,78 @@ static const struct cx88_board cx88_boards[] = { .gpio3 = 0x0000, }, }, + [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36] = { + .name = "Leadtek TV2000 XP Global (SC4100)", + .tuner_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C04, /* pin 18 = 1, pin 19 = 0 */ + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C0C, /* pin 18 = 1, pin 19 = 1 */ + .gpio3 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x0000, + .gpio2 = 0x0C00, /* pin 18 = 0, pin 19 = 0 */ + .gpio3 = 0x0000, + }, + }, + [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43] = { + .name = "Leadtek TV2000 XP Global (XC4100)", + .tuner_type = TUNER_XC4000, + .tuner_addr = 0x61, + .radio_type = UNSET, + .radio_addr = ADDR_UNSET, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6040, /* pin 14 = 1, pin 13 = 0 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 14 = 1, pin 13 = 1 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6060, /* pin 14 = 1, pin 13 = 1 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0400, /* pin 2 = 0 */ + .gpio1 = 0x6000, /* pin 14 = 1, pin 13 = 0 */ + .gpio2 = 0x0000, + .gpio3 = 0x0000, + }, + }, [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = { .name = "PowerColor RA330", /* Long names may confuse LIRC. */ .tuner_type = TUNER_XC2028, @@ -2719,6 +2791,21 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x6618, .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, }, { + /* TV2000 XP Global [107d:6618] */ + .subvendor = 0x107d, + .subdevice = 0x6619, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, + }, { + /* WinFast TV2000 XP Global with XC4000 tuner */ + .subvendor = 0x107d, + .subdevice = 0x6f36, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36, + }, { + /* WinFast TV2000 XP Global with XC4000 tuner and different GPIOs */ + .subvendor = 0x107d, + .subdevice = 0x6f43, + .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43, + }, { .subvendor = 0xb034, .subdevice = 0x3034, .card = CX88_BOARD_PROF_7301, @@ -3075,6 +3162,8 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core, switch (core->boardnr) { case CX88_BOARD_WINFAST_DTV1800H_XC4000: case CX88_BOARD_WINFAST_DTV2000H_PLUS: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: return cx88_xc4000_winfast2000h_plus_callback(core, command, arg); } @@ -3232,6 +3321,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) cx_set(MO_GP0_IO, 0x00001010); break; + case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR4000: /* Init GPIO */ @@ -3250,6 +3340,8 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_WINFAST_DTV1800H_XC4000: case CX88_BOARD_WINFAST_DTV2000H_PLUS: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: cx88_xc4000_winfast2000h_plus_callback(core, XC4000_TUNER_RESET, 0); break; diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index cf3d33ab541b..003937cd72f5 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -815,9 +815,9 @@ static const u8 samsung_smt_7020_inittab[] = { }; -static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx8802_dev *dev = fe->dvb->priv; u8 buf[4]; u32 div; @@ -827,14 +827,14 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe, .buf = buf, .len = sizeof(buf) }; - div = params->frequency / 125; + div = c->frequency / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x84; /* 0xC4 */ buf[3] = 0x00; - if (params->frequency < 1500000) + if (c->frequency < 1500000) buf[3] |= 0x10; if (fe->ops.i2c_gate_ctrl) @@ -954,6 +954,7 @@ static int dvb_register(struct cx8802_dev *dev) struct cx88_core *core = dev->core; struct videobuf_dvb_frontend *fe0, *fe1 = NULL; int mfe_shared = 0; /* bus not shared by default */ + int res = -EINVAL; if (0 != core->i2c_rc) { printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); @@ -999,7 +1000,6 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_WINFAST_DTV2000H: - case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1013,6 +1013,17 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; } break; + case CX88_BOARD_WINFAST_DTV2000H_J: + fe0->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) { + if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216MEX_MK3)) + goto frontend_detach; + } + break; case CX88_BOARD_HAUPPAUGE_HVR3000: /* MFE frontend 1 */ mfe_shared = 1; @@ -1566,13 +1577,16 @@ static int dvb_register(struct cx8802_dev *dev) call_all(core, core, s_power, 0); /* register everything */ - return videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, - &dev->pci->dev, adapter_nr, mfe_shared, NULL); + res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev, + &dev->pci->dev, adapter_nr, mfe_shared, NULL); + if (res) + goto frontend_detach; + return res; frontend_detach: core->gate_ctrl = NULL; videobuf_dvb_dealloc_frontends(&dev->frontends); - return -EINVAL; + return res; } /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index a1fe0abb6e43..de0f1af74e41 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -132,7 +132,7 @@ static void do_i2c_scan(const char *name, struct i2c_client *c) } } -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) { /* Prevents usage of invalid delay values */ diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index e614201b5ed3..ebf448c48ca3 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -103,6 +103,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) case CX88_BOARD_WINFAST_DTV1800H_XC4000: case CX88_BOARD_WINFAST_DTV2000H_PLUS: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900); auxgpio = gpio; break; @@ -302,6 +304,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_WINFAST2000XP_EXPERT: case CX88_BOARD_WINFAST_DTV1000: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36: + case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43: ir_codes = RC_MAP_WINFAST; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index fa8d307e1a3d..c9659def2a78 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -244,6 +244,8 @@ extern const struct sram_channel const cx88_sram_channels[]; #define CX88_BOARD_TEVII_S464 86 #define CX88_BOARD_WINFAST_DTV2000H_PLUS 87 #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 +#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89 +#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c index bd443ee76fff..f83baf3a52b0 100644 --- a/drivers/media/video/davinci/dm355_ccdc.c +++ b/drivers/media/video/davinci/dm355_ccdc.c @@ -1069,15 +1069,4 @@ static struct platform_driver dm355_ccdc_driver = { .probe = dm355_ccdc_probe, }; -static int __init dm355_ccdc_init(void) -{ - return platform_driver_register(&dm355_ccdc_driver); -} - -static void __exit dm355_ccdc_exit(void) -{ - platform_driver_unregister(&dm355_ccdc_driver); -} - -module_init(dm355_ccdc_init); -module_exit(dm355_ccdc_exit); +module_platform_driver(dm355_ccdc_driver); diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index 8051c2956478..9303fe553b07 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -1078,15 +1078,4 @@ static struct platform_driver dm644x_ccdc_driver = { .probe = dm644x_ccdc_probe, }; -static int __init dm644x_ccdc_init(void) -{ - return platform_driver_register(&dm644x_ccdc_driver); -} - -static void __exit dm644x_ccdc_exit(void) -{ - platform_driver_unregister(&dm644x_ccdc_driver); -} - -module_init(dm644x_ccdc_init); -module_exit(dm644x_ccdc_exit); +module_platform_driver(dm644x_ccdc_driver); diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c index 29c29c668596..1e63852374be 100644 --- a/drivers/media/video/davinci/isif.c +++ b/drivers/media/video/davinci/isif.c @@ -1156,17 +1156,6 @@ static struct platform_driver isif_driver = { .probe = isif_probe, }; -static int __init isif_init(void) -{ - return platform_driver_register(&isif_driver); -} - -static void isif_exit(void) -{ - platform_driver_unregister(&isif_driver); -} - -module_init(isif_init); -module_exit(isif_exit); +module_platform_driver(isif_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c index d773d30de221..c4a82a1a8a97 100644 --- a/drivers/media/video/davinci/vpbe.c +++ b/drivers/media/video/davinci/vpbe.c @@ -141,11 +141,12 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, return 0; } -static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) +static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, + int output_index) { struct vpbe_config *cfg = vpbe_dev->cfg; struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; + int curr_output = output_index; int i; if (NULL == mode) @@ -245,6 +246,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) struct encoder_config_info *curr_enc_info = vpbe_current_encoder_info(vpbe_dev); struct vpbe_config *cfg = vpbe_dev->cfg; + struct venc_platform_data *venc_device = vpbe_dev->venc_device; + enum v4l2_mbus_pixelcode if_params; int enc_out_index; int sd_index; int ret = 0; @@ -274,6 +277,8 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) goto out; } + if_params = cfg->outputs[index].if_params; + venc_device->setup_if_config(if_params); if (ret) goto out; } @@ -293,7 +298,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) * encoder. */ ret = vpbe_get_mode_info(vpbe_dev, - cfg->outputs[index].default_mode); + cfg->outputs[index].default_mode, index); if (!ret) { struct osd_state *osd_device = vpbe_dev->osd_device; @@ -367,6 +372,11 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, s_dv_preset, dv_preset); + if (!ret && (vpbe_dev->amp != NULL)) { + /* Call amplifier subdevice */ + ret = v4l2_subdev_call(vpbe_dev->amp, video, + s_dv_preset, dv_preset); + } /* set the lcd controller output for the given mode */ if (!ret) { struct osd_state *osd_device = vpbe_dev->osd_device; @@ -566,6 +576,8 @@ static int platform_device_get(struct device *dev, void *data) if (strcmp("vpbe-osd", pdev->name) == 0) vpbe_dev->osd_device = platform_get_drvdata(pdev); + if (strcmp("vpbe-venc", pdev->name) == 0) + vpbe_dev->venc_device = dev_get_platdata(&pdev->dev); return 0; } @@ -584,6 +596,7 @@ static int platform_device_get(struct device *dev, void *data) static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) { struct encoder_config_info *enc_info; + struct amp_config_info *amp_info; struct v4l2_subdev **enc_subdev; struct osd_state *osd_device; struct i2c_adapter *i2c_adap; @@ -704,6 +717,32 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" " currently not supported"); } + /* Add amplifier subdevice for dm365 */ + if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && + vpbe_dev->cfg->amp != NULL) { + amp_info = vpbe_dev->cfg->amp; + if (amp_info->is_i2c) { + vpbe_dev->amp = v4l2_i2c_new_subdev_board( + &vpbe_dev->v4l2_dev, i2c_adap, + &_info->board_info, NULL); + if (!vpbe_dev->amp) { + v4l2_err(&vpbe_dev->v4l2_dev, + "amplifier %s failed to register", + amp_info->module_name); + ret = -ENODEV; + goto vpbe_fail_amp_register; + } + v4l2_info(&vpbe_dev->v4l2_dev, + "v4l2 sub device %s registered\n", + amp_info->module_name); + } else { + vpbe_dev->amp = NULL; + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers" + " currently not supported"); + } + } else { + vpbe_dev->amp = NULL; + } /* set the current encoder and output to that of venc by default */ vpbe_dev->current_sd_index = 0; @@ -731,6 +770,8 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) /* TBD handling of bootargs for default output and mode */ return 0; +vpbe_fail_amp_register: + kfree(vpbe_dev->amp); vpbe_fail_sd_register: kfree(vpbe_dev->encoders); vpbe_fail_v4l2_device: @@ -757,6 +798,7 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) clk_put(vpbe_dev->dac_clk); + kfree(vpbe_dev->amp); kfree(vpbe_dev->encoders); vpbe_dev->initialized = 0; /* disable vpss clocks */ @@ -811,8 +853,10 @@ static __devinit int vpbe_probe(struct platform_device *pdev) if (cfg->outputs->num_modes > 0) vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; - else + else { + kfree(vpbe_dev); return -ENODEV; + } /* set the driver data in platform device */ platform_set_drvdata(pdev, vpbe_dev); @@ -839,26 +883,4 @@ static struct platform_driver vpbe_driver = { .remove = vpbe_remove, }; -/** - * vpbe_init: initialize the vpbe driver - * - * This function registers device and driver to the kernel - */ -static __init int vpbe_init(void) -{ - return platform_driver_register(&vpbe_driver); -} - -/** - * vpbe_cleanup : cleanup function for vpbe driver - * - * This will un-registers the device and driver to the kernel - */ -static void vpbe_cleanup(void) -{ - platform_driver_unregister(&vpbe_driver); -} - -/* Function for module initialization and cleanup */ -module_init(vpbe_init); -module_exit(vpbe_cleanup); +module_platform_driver(vpbe_driver); diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c index 8588a86d9b45..1f3b1c729252 100644 --- a/drivers/media/video/davinci/vpbe_display.c +++ b/drivers/media/video/davinci/vpbe_display.c @@ -1746,15 +1746,16 @@ static __devinit int vpbe_display_probe(struct platform_device *pdev) for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { if (register_device(disp_dev->dev[i], disp_dev, pdev)) { err = -ENODEV; - goto probe_out; + goto probe_out_irq; } } printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); return 0; -probe_out: +probe_out_irq: free_irq(res->start, disp_dev); +probe_out: for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { /* Get the pointer to the layer object */ vpbe_display_layer = disp_dev->dev[k]; @@ -1816,43 +1817,7 @@ static struct platform_driver vpbe_display_driver = { .remove = __devexit_p(vpbe_display_remove), }; -/* - * vpbe_display_init() - * This function registers device and driver to the kernel, requests irq - * handler and allocates memory for layer objects - */ -static __devinit int vpbe_display_init(void) -{ - int err; - - printk(KERN_DEBUG "vpbe_display_init\n"); - - /* Register driver to the kernel */ - err = platform_driver_register(&vpbe_display_driver); - if (0 != err) - return err; - - printk(KERN_DEBUG "vpbe_display_init:" - "VPBE V4L2 Display Driver V1.0 loaded\n"); - return 0; -} - -/* - * vpbe_display_cleanup() - * This function un-registers device and driver to the kernel, frees requested - * irq handler and de-allocates memory allocated for layer objects. - */ -static void vpbe_display_cleanup(void) -{ - printk(KERN_DEBUG "vpbe_display_cleanup\n"); - - /* platform driver unregister */ - platform_driver_unregister(&vpbe_display_driver); -} - -/* Function for module initialization and cleanup */ -module_init(vpbe_display_init); -module_exit(vpbe_display_cleanup); +module_platform_driver(vpbe_display_driver); MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c index ceccf4302518..d6488b79ae3b 100644 --- a/drivers/media/video/davinci/vpbe_osd.c +++ b/drivers/media/video/davinci/vpbe_osd.c @@ -248,11 +248,29 @@ static void _osd_set_rec601_attenuation(struct osd_state *sd, osd_modify(sd, OSD_OSDWIN0MD_ATN0E, enable ? OSD_OSDWIN0MD_ATN0E : 0, OSD_OSDWIN0MD); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_modify(sd, OSD_OSDWIN0MD_ATN0E, + enable ? OSD_OSDWIN0MD_ATN0E : 0, + OSD_OSDWIN0MD); + else if ((sd->vpbe_type == VPBE_VERSION_3) || + (sd->vpbe_type == VPBE_VERSION_2)) + osd_modify(sd, OSD_EXTMODE_ATNOSD0EN, + enable ? OSD_EXTMODE_ATNOSD0EN : 0, + OSD_EXTMODE); break; case OSDWIN_OSD1: osd_modify(sd, OSD_OSDWIN1MD_ATN1E, enable ? OSD_OSDWIN1MD_ATN1E : 0, OSD_OSDWIN1MD); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_modify(sd, OSD_OSDWIN1MD_ATN1E, + enable ? OSD_OSDWIN1MD_ATN1E : 0, + OSD_OSDWIN1MD); + else if ((sd->vpbe_type == VPBE_VERSION_3) || + (sd->vpbe_type == VPBE_VERSION_2)) + osd_modify(sd, OSD_EXTMODE_ATNOSD1EN, + enable ? OSD_EXTMODE_ATNOSD1EN : 0, + OSD_EXTMODE); break; } } @@ -273,15 +291,71 @@ static void _osd_set_blending_factor(struct osd_state *sd, } } +static void _osd_enable_rgb888_pixblend(struct osd_state *sd, + enum osd_win_layer osdwin) +{ + + osd_modify(sd, OSD_MISCCTL_BLDSEL, 0, OSD_MISCCTL); + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_EXTMODE_OSD0BLDCHR, + OSD_EXTMODE_OSD0BLDCHR, OSD_EXTMODE); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_EXTMODE_OSD1BLDCHR, + OSD_EXTMODE_OSD1BLDCHR, OSD_EXTMODE); + break; + } +} + static void _osd_enable_color_key(struct osd_state *sd, enum osd_win_layer osdwin, unsigned colorkey, enum osd_pix_format pixfmt) { switch (pixfmt) { + case PIXFMT_1BPP: + case PIXFMT_2BPP: + case PIXFMT_4BPP: + case PIXFMT_8BPP: + if (sd->vpbe_type == VPBE_VERSION_3) { + switch (osdwin) { + case OSDWIN_OSD0: + osd_modify(sd, OSD_TRANSPBMPIDX_BMP0, + colorkey << + OSD_TRANSPBMPIDX_BMP0_SHIFT, + OSD_TRANSPBMPIDX); + break; + case OSDWIN_OSD1: + osd_modify(sd, OSD_TRANSPBMPIDX_BMP1, + colorkey << + OSD_TRANSPBMPIDX_BMP1_SHIFT, + OSD_TRANSPBMPIDX); + break; + } + } + break; case PIXFMT_RGB565: - osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, - OSD_TRANSPVAL); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, + OSD_TRANSPVAL); + else if (sd->vpbe_type == VPBE_VERSION_3) + osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, + OSD_TRANSPVALL); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + if (sd->vpbe_type == VPBE_VERSION_3) + osd_modify(sd, OSD_TRANSPVALU_Y, colorkey, + OSD_TRANSPVALU); + break; + case PIXFMT_RGB888: + if (sd->vpbe_type == VPBE_VERSION_3) { + osd_write(sd, colorkey & OSD_TRANSPVALL_RGBL, + OSD_TRANSPVALL); + osd_modify(sd, OSD_TRANSPVALU_RGBU, colorkey >> 16, + OSD_TRANSPVALU); + } break; default: break; @@ -470,23 +544,188 @@ static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, return 0; } +#define OSD_SRC_ADDR_HIGH4 0x7800000 +#define OSD_SRC_ADDR_HIGH7 0x7F0000 +#define OSD_SRCADD_OFSET_SFT 23 +#define OSD_SRCADD_ADD_SFT 16 +#define OSD_WINADL_MASK 0xFFFF +#define OSD_WINOFST_MASK 0x1000 +#define VPBE_REG_BASE 0x80000000 + static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, unsigned long fb_base_phys, unsigned long cbcr_ofst) { - switch (layer) { - case WIN_OSD0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); - break; - case WIN_VID0: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); - break; - case WIN_OSD1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); - break; - case WIN_VID1: - osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); - break; + + if (sd->vpbe_type == VPBE_VERSION_1) { + switch (layer) { + case WIN_OSD0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); + break; + case WIN_VID0: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); + break; + case WIN_OSD1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); + break; + case WIN_VID1: + osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); + break; + } + } else if (sd->vpbe_type == VPBE_VERSION_3) { + unsigned long fb_offset_32 = + (fb_base_phys - VPBE_REG_BASE) >> 5; + + switch (layer) { + case WIN_OSD0: + osd_modify(sd, OSD_OSDWINADH_O0AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O0AH_SHIFT), + OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_OSDWIN0ADL_O0AL, + OSD_OSDWIN0ADL); + break; + case WIN_VID0: + osd_modify(sd, OSD_VIDWINADH_V0AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V0AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_VIDWIN0ADL_V0AL, + OSD_VIDWIN0ADL); + break; + case WIN_OSD1: + osd_modify(sd, OSD_OSDWINADH_O1AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O1AH_SHIFT), + OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_OSDWIN1ADL_O1AL, + OSD_OSDWIN1ADL); + break; + case WIN_VID1: + osd_modify(sd, OSD_VIDWINADH_V1AH, + fb_offset_32 >> (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V1AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_VIDWIN1ADL_V1AL, + OSD_VIDWIN1ADL); + break; + } + } else if (sd->vpbe_type == VPBE_VERSION_2) { + struct osd_window_state *win = &sd->win[layer]; + unsigned long fb_offset_32, cbcr_offset_32; + + fb_offset_32 = fb_base_phys - VPBE_REG_BASE; + if (cbcr_ofst) + cbcr_offset_32 = cbcr_ofst; + else + cbcr_offset_32 = win->lconfig.line_length * + win->lconfig.ysize; + cbcr_offset_32 += fb_offset_32; + fb_offset_32 = fb_offset_32 >> 5; + cbcr_offset_32 = cbcr_offset_32 >> 5; + /* + * DM365: start address is 27-bit long address b26 - b23 are + * in offset register b12 - b9, and * bit 26 has to be '1' + */ + if (win->lconfig.pixfmt == PIXFMT_NV12) { + switch (layer) { + case WIN_VID0: + case WIN_VID1: + /* Y is in VID0 */ + osd_modify(sd, OSD_VIDWIN0OFST_V0AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN0OFST); + osd_modify(sd, OSD_VIDWINADH_V0AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V0AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN0ADL); + /* CbCr is in VID1 */ + osd_modify(sd, OSD_VIDWIN1OFST_V1AH, + ((cbcr_offset_32 & + OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN1OFST); + osd_modify(sd, OSD_VIDWINADH_V1AH, + (cbcr_offset_32 & + OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V1AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, cbcr_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN1ADL); + break; + default: + break; + } + } + + switch (layer) { + case WIN_OSD0: + osd_modify(sd, OSD_OSDWIN0OFST_O0AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, + OSD_OSDWIN0OFST); + osd_modify(sd, OSD_OSDWINADH_O0AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O0AH_SHIFT), OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_OSDWIN0ADL); + break; + case WIN_VID0: + if (win->lconfig.pixfmt != PIXFMT_NV12) { + osd_modify(sd, OSD_VIDWIN0OFST_V0AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN0OFST); + osd_modify(sd, OSD_VIDWINADH_V0AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V0AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN0ADL); + } + break; + case WIN_OSD1: + osd_modify(sd, OSD_OSDWIN1OFST_O1AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | OSD_WINOFST_MASK, + OSD_OSDWIN1OFST); + osd_modify(sd, OSD_OSDWINADH_O1AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_OSDWINADH_O1AH_SHIFT), + OSD_OSDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_OSDWIN1ADL); + break; + case WIN_VID1: + if (win->lconfig.pixfmt != PIXFMT_NV12) { + osd_modify(sd, OSD_VIDWIN1OFST_V1AH, + ((fb_offset_32 & OSD_SRC_ADDR_HIGH4) >> + (OSD_SRCADD_OFSET_SFT - + OSD_WINOFST_AH_SHIFT)) | + OSD_WINOFST_MASK, OSD_VIDWIN1OFST); + osd_modify(sd, OSD_VIDWINADH_V1AH, + (fb_offset_32 & OSD_SRC_ADDR_HIGH7) >> + (OSD_SRCADD_ADD_SFT - + OSD_VIDWINADH_V1AH_SHIFT), + OSD_VIDWINADH); + osd_write(sd, fb_offset_32 & OSD_WINADL_MASK, + OSD_VIDWIN1ADL); + } + break; + } } } @@ -545,7 +784,7 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, { struct osd_state *osd = sd; struct osd_window_state *win = &osd->win[layer]; - int bad_config; + int bad_config = 0; /* verify that the pixel format is compatible with the layer */ switch (lconfig->pixfmt) { @@ -554,17 +793,25 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, case PIXFMT_4BPP: case PIXFMT_8BPP: case PIXFMT_RGB565: - bad_config = !is_osd_win(layer); + if (osd->vpbe_type == VPBE_VERSION_1) + bad_config = !is_vid_win(layer); break; case PIXFMT_YCbCrI: case PIXFMT_YCrCbI: bad_config = !is_vid_win(layer); break; case PIXFMT_RGB888: - bad_config = !is_vid_win(layer); + if (osd->vpbe_type == VPBE_VERSION_1) + bad_config = !is_vid_win(layer); + else if ((osd->vpbe_type == VPBE_VERSION_3) || + (osd->vpbe_type == VPBE_VERSION_2)) + bad_config = !is_osd_win(layer); break; case PIXFMT_NV12: - bad_config = 1; + if (osd->vpbe_type != VPBE_VERSION_2) + bad_config = 1; + else + bad_config = is_osd_win(layer); break; case PIXFMT_OSD_ATTR: bad_config = (layer != WIN_OSD1); @@ -584,7 +831,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, /* DM6446: */ /* only one OSD window at a time can use RGB pixel formats */ - if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { + if ((osd->vpbe_type == VPBE_VERSION_1) && + is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { enum osd_pix_format pixfmt; if (layer == WIN_OSD0) pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; @@ -602,7 +850,8 @@ static int try_layer_config(struct osd_state *sd, enum osd_layer layer, } /* DM6446: only one video window at a time can use RGB888 */ - if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { + if ((osd->vpbe_type == VPBE_VERSION_1) && is_vid_win(layer) && + lconfig->pixfmt == PIXFMT_RGB888) { enum osd_pix_format pixfmt; if (layer == WIN_VID0) @@ -652,7 +901,8 @@ static void _osd_disable_vid_rgb888(struct osd_state *sd) * The caller must ensure that neither video window is currently * configured for RGB888 pixel format. */ - osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_1) + osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); } static void _osd_enable_vid_rgb888(struct osd_state *sd, @@ -665,13 +915,14 @@ static void _osd_enable_vid_rgb888(struct osd_state *sd, * currently configured for RGB888 pixel format, as this routine will * disable RGB888 pixel format for the other window. */ - if (layer == WIN_VID0) { - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN, OSD_MISCCTL); - } else if (layer == WIN_VID1) { - osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, - OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_1) { + if (layer == WIN_VID0) + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN, OSD_MISCCTL); + else if (layer == WIN_VID1) + osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, + OSD_MISCCTL); } } @@ -697,9 +948,30 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, switch (layer) { case WIN_OSD0: - winmd_mask |= OSD_OSDWIN0MD_RGB0E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN0MD_RGB0E; + if (sd->vpbe_type == VPBE_VERSION_1) { + winmd_mask |= OSD_OSDWIN0MD_RGB0E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN0MD_RGB0E; + } else if ((sd->vpbe_type == VPBE_VERSION_3) || + (sd->vpbe_type == VPBE_VERSION_2)) { + winmd_mask |= OSD_OSDWIN0MD_BMP0MD; + switch (lconfig->pixfmt) { + case PIXFMT_RGB565: + winmd |= (1 << + OSD_OSDWIN0MD_BMP0MD_SHIFT); + break; + case PIXFMT_RGB888: + winmd |= (2 << OSD_OSDWIN0MD_BMP0MD_SHIFT); + _osd_enable_rgb888_pixblend(sd, OSDWIN_OSD0); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + winmd |= (3 << OSD_OSDWIN0MD_BMP0MD_SHIFT); + break; + default: + break; + } + } winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; @@ -749,12 +1021,59 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, * For YUV420P format the register contents are * duplicated in both VID registers */ + if ((sd->vpbe_type == VPBE_VERSION_2) && + (lconfig->pixfmt == PIXFMT_NV12)) { + /* other window also */ + if (lconfig->interlaced) { + winmd_mask |= OSD_VIDWINMD_VFF1; + winmd |= OSD_VIDWINMD_VFF1; + osd_modify(sd, winmd_mask, winmd, + OSD_VIDWINMD); + } + + osd_modify(sd, OSD_MISCCTL_S420D, + OSD_MISCCTL_S420D, OSD_MISCCTL); + osd_write(sd, lconfig->line_length >> 5, + OSD_VIDWIN1OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); + /* + * if NV21 pixfmt and line length not 32B + * aligned (e.g. NTSC), Need to set window + * X pixel size to be 32B aligned as well + */ + if (lconfig->xsize % 32) { + osd_write(sd, + ((lconfig->xsize + 31) & ~31), + OSD_VIDWIN1XL); + osd_write(sd, + ((lconfig->xsize + 31) & ~31), + OSD_VIDWIN0XL); + } + } else if ((sd->vpbe_type == VPBE_VERSION_2) && + (lconfig->pixfmt != PIXFMT_NV12)) { + osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, + OSD_MISCCTL); + } + if (lconfig->interlaced) { osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos >> 1, + OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize >> 1, + OSD_VIDWIN1YL); + } } else { osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + } } break; case WIN_OSD1: @@ -764,14 +1083,43 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, * attribute mode to a normal mode. */ if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { - winmd_mask |= - OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | - OSD_OSDWIN1MD_CLUTS1 | - OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + if (sd->vpbe_type == VPBE_VERSION_1) { + winmd_mask |= OSD_OSDWIN1MD_ATN1E | + OSD_OSDWIN1MD_RGB1E | OSD_OSDWIN1MD_CLUTS1 | + OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; + } else { + winmd_mask |= OSD_OSDWIN1MD_BMP1MD | + OSD_OSDWIN1MD_CLUTS1 | OSD_OSDWIN1MD_BLND1 | + OSD_OSDWIN1MD_TE1; + } } else { - winmd_mask |= OSD_OSDWIN1MD_RGB1E; - if (lconfig->pixfmt == PIXFMT_RGB565) - winmd |= OSD_OSDWIN1MD_RGB1E; + if (sd->vpbe_type == VPBE_VERSION_1) { + winmd_mask |= OSD_OSDWIN1MD_RGB1E; + if (lconfig->pixfmt == PIXFMT_RGB565) + winmd |= OSD_OSDWIN1MD_RGB1E; + } else if ((sd->vpbe_type == VPBE_VERSION_3) + || (sd->vpbe_type == VPBE_VERSION_2)) { + winmd_mask |= OSD_OSDWIN1MD_BMP1MD; + switch (lconfig->pixfmt) { + case PIXFMT_RGB565: + winmd |= + (1 << OSD_OSDWIN1MD_BMP1MD_SHIFT); + break; + case PIXFMT_RGB888: + winmd |= + (2 << OSD_OSDWIN1MD_BMP1MD_SHIFT); + _osd_enable_rgb888_pixblend(sd, + OSDWIN_OSD1); + break; + case PIXFMT_YCbCrI: + case PIXFMT_YCrCbI: + winmd |= + (3 << OSD_OSDWIN1MD_BMP1MD_SHIFT); + break; + default: + break; + } + } winmd_mask |= OSD_OSDWIN1MD_BMW1; switch (lconfig->pixfmt) { @@ -822,15 +1170,45 @@ static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, * For YUV420P format the register contents are * duplicated in both VID registers */ - osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, - OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_2) { + if (lconfig->pixfmt == PIXFMT_NV12) { + /* other window also */ + if (lconfig->interlaced) { + winmd_mask |= OSD_VIDWINMD_VFF0; + winmd |= OSD_VIDWINMD_VFF0; + osd_modify(sd, winmd_mask, winmd, + OSD_VIDWINMD); + } + osd_modify(sd, OSD_MISCCTL_S420D, + OSD_MISCCTL_S420D, OSD_MISCCTL); + osd_write(sd, lconfig->line_length >> 5, + OSD_VIDWIN0OFST); + osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); + osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); + } else { + osd_modify(sd, OSD_MISCCTL_S420D, + ~OSD_MISCCTL_S420D, OSD_MISCCTL); + } + } if (lconfig->interlaced) { osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos >> 1, + OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize >> 1, + OSD_VIDWIN0YL); + } } else { osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); + if ((sd->vpbe_type == VPBE_VERSION_2) && + lconfig->pixfmt == PIXFMT_NV12) { + osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); + osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); + } } break; } @@ -1089,6 +1467,11 @@ static void _osd_init(struct osd_state *sd) osd_write(sd, 0, OSD_OSDWIN1MD); osd_write(sd, 0, OSD_RECTCUR); osd_write(sd, 0, OSD_MISCCTL); + if (sd->vpbe_type == VPBE_VERSION_3) { + osd_write(sd, 0, OSD_VBNDRY); + osd_write(sd, 0, OSD_EXTMODE); + osd_write(sd, OSD_MISCCTL_DMANG, OSD_MISCCTL); + } } static void osd_set_left_margin(struct osd_state *sd, u32 val) @@ -1110,6 +1493,14 @@ static int osd_initialize(struct osd_state *osd) /* set default Cb/Cr order */ osd->yc_pixfmt = PIXFMT_YCbCrI; + if (osd->vpbe_type == VPBE_VERSION_3) { + /* + * ROM CLUT1 on the DM355 is similar (identical?) to ROM CLUT0 + * on the DM6446, so make ROM_CLUT1 the default on the DM355. + */ + osd->rom_clut = ROM_CLUT1; + } + _osd_set_field_inversion(osd, osd->field_inversion); _osd_set_rom_clut(osd, osd->rom_clut); @@ -1208,23 +1599,7 @@ static struct platform_driver osd_driver = { }, }; -static int osd_init(void) -{ - if (platform_driver_register(&osd_driver)) { - printk(KERN_ERR "Unable to register davinci osd driver\n"); - return -ENODEV; - } - - return 0; -} - -static void osd_exit(void) -{ - platform_driver_unregister(&osd_driver); -} - -module_init(osd_init); -module_exit(osd_exit); +module_platform_driver(osd_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c index 03a3e5c65ee7..00e80f59d5d5 100644 --- a/drivers/media/video/davinci/vpbe_venc.c +++ b/drivers/media/video/davinci/vpbe_venc.c @@ -99,6 +99,8 @@ static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) return val; } +#define VDAC_COMPONENT 0x543 +#define VDAC_S_VIDEO 0x210 /* This function sets the dac of the VPBE for various outputs */ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) @@ -109,11 +111,12 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) venc_write(sd, VENC_DACSEL, 0); break; case 1: - v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); - venc_write(sd, VENC_DACSEL, 0x210); + v4l2_dbg(debug, 1, sd, "Setting output to Component\n"); + venc_write(sd, VENC_DACSEL, VDAC_COMPONENT); break; - case 2: - venc_write(sd, VENC_DACSEL, 0x543); + case 2: + v4l2_dbg(debug, 1, sd, "Setting output to S-video\n"); + venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO); break; default: return -EINVAL; @@ -124,6 +127,8 @@ static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) { + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); if (benable) { @@ -155,7 +160,8 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) /* Disable LCD output control (accepting default polarity) */ venc_write(sd, VENC_LCDOUT, 0); - venc_write(sd, VENC_CMPNT, 0x100); + if (pdata->venc_type != VPBE_VERSION_3) + venc_write(sd, VENC_CMPNT, 0x100); venc_write(sd, VENC_HSPLS, 0); venc_write(sd, VENC_HINT, 0); venc_write(sd, VENC_HSTART, 0); @@ -178,11 +184,14 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) } } +#define VDAC_CONFIG_SD_V3 0x0E21A6B6 +#define VDAC_CONFIG_SD_V2 0x081141CF /* * setting NTSC mode */ static int venc_set_ntsc(struct v4l2_subdev *sd) { + u32 val; struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; @@ -195,12 +204,22 @@ static int venc_set_ntsc(struct v4l2_subdev *sd) venc_enabledigitaloutput(sd, 0); - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + if (pdata->venc_type == VPBE_VERSION_3) { + venc_write(sd, VENC_CLKCTL, 0x01); + venc_write(sd, VENC_VIDCTL, 0); + val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3); + } else if (pdata->venc_type == VPBE_VERSION_2) { + venc_write(sd, VENC_CLKCTL, 0x01); + venc_write(sd, VENC_VIDCTL, 0); + vdaccfg_write(sd, VDAC_CONFIG_SD_V2); + } else { + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); + } venc_write(sd, VENC_VMOD, 0); venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), @@ -220,6 +239,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd) static int venc_set_pal(struct v4l2_subdev *sd) { struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); @@ -230,10 +250,20 @@ static int venc_set_pal(struct v4l2_subdev *sd) venc_enabledigitaloutput(sd, 0); - /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ - venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); - /* Set REC656 Mode */ - venc_write(sd, VENC_YCCCTL, 0x1); + if (pdata->venc_type == VPBE_VERSION_3) { + venc_write(sd, VENC_CLKCTL, 0x1); + venc_write(sd, VENC_VIDCTL, 0); + vdaccfg_write(sd, VDAC_CONFIG_SD_V3); + } else if (pdata->venc_type == VPBE_VERSION_2) { + venc_write(sd, VENC_CLKCTL, 0x1); + venc_write(sd, VENC_VIDCTL, 0); + vdaccfg_write(sd, VDAC_CONFIG_SD_V2); + } else { + /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ + venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); + /* Set REC656 Mode */ + venc_write(sd, VENC_YCCCTL, 0x1); + } venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, VENC_SYNCCTL_OVD); @@ -252,6 +282,7 @@ static int venc_set_pal(struct v4l2_subdev *sd) return 0; } +#define VDAC_CONFIG_HD_V2 0x081141EF /* * venc_set_480p59_94 * @@ -263,6 +294,9 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) struct venc_platform_data *pdata = venc->pdata; v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); + if ((pdata->venc_type != VPBE_VERSION_1) && + (pdata->venc_type != VPBE_VERSION_2)) + return -EINVAL; /* Setup clock at VPSS & VENC for SD */ if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) @@ -270,12 +304,18 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) venc_enabledigitaloutput(sd, 0); + if (pdata->venc_type == VPBE_VERSION_2) + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); venc_write(sd, VENC_OSDCLK0, 0); venc_write(sd, VENC_OSDCLK1, 1); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); + + if (pdata->venc_type == VPBE_VERSION_1) { + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + } + venc_write(sd, VENC_VMOD, 0); venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), VENC_VMOD_VIE); @@ -302,19 +342,27 @@ static int venc_set_576p50(struct v4l2_subdev *sd) v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); + if ((pdata->venc_type != VPBE_VERSION_1) && + (pdata->venc_type != VPBE_VERSION_2)) + return -EINVAL; /* Setup clock at VPSS & VENC for SD */ if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); + if (pdata->venc_type == VPBE_VERSION_2) + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); + venc_write(sd, VENC_OSDCLK0, 0); venc_write(sd, VENC_OSDCLK1, 1); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, - VENC_VDPRO_DAFRQ); - venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, - VENC_VDPRO_DAUPS); + if (pdata->venc_type == VPBE_VERSION_1) { + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, + VENC_VDPRO_DAFRQ); + venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, + VENC_VDPRO_DAUPS); + } venc_write(sd, VENC_VMOD, 0); venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), @@ -330,6 +378,63 @@ static int venc_set_576p50(struct v4l2_subdev *sd) return 0; } +/* + * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only + */ +static int venc_set_720p60_internal(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + venc_write(sd, VENC_VMOD, 0); + /* DM365 component HD mode */ + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + venc_write(sd, VENC_XHINTVL, 0); + return 0; +} + +/* + * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only + */ +static int venc_set_1080i30_internal(struct v4l2_subdev *sd) +{ + struct venc_state *venc = to_state(sd); + struct venc_platform_data *pdata = venc->pdata; + + if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0) + return -EINVAL; + + venc_enabledigitaloutput(sd, 0); + + venc_write(sd, VENC_OSDCLK0, 0); + venc_write(sd, VENC_OSDCLK1, 1); + + + venc_write(sd, VENC_VMOD, 0); + /* DM365 component HD mode */ + venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), + VENC_VMOD_VIE); + venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); + venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT), + VENC_VMOD_TVTYP); + venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); + venc_write(sd, VENC_XHINTVL, 0); + return 0; +} + static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); @@ -345,13 +450,30 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) static int venc_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *dv_preset) { + struct venc_state *venc = to_state(sd); + int ret; + v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); if (dv_preset->preset == V4L2_DV_576P50) return venc_set_576p50(sd); else if (dv_preset->preset == V4L2_DV_480P59_94) return venc_set_480p59_94(sd); - + else if ((dv_preset->preset == V4L2_DV_720P60) && + (venc->pdata->venc_type == VPBE_VERSION_2)) { + /* TBD setup internal 720p mode here */ + ret = venc_set_720p60_internal(sd); + /* for DM365 VPBE, there is DAC inside */ + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); + return ret; + } else if ((dv_preset->preset == V4L2_DV_1080I30) && + (venc->pdata->venc_type == VPBE_VERSION_2)) { + /* TBD setup internal 1080i mode here */ + ret = venc_set_1080i30_internal(sd); + /* for DM365 VPBE, there is DAC inside */ + vdaccfg_write(sd, VDAC_CONFIG_HD_V2); + return ret; + } return -EINVAL; } @@ -508,11 +630,41 @@ static int venc_probe(struct platform_device *pdev) goto release_venc_mem_region; } + if (venc->pdata->venc_type != VPBE_VERSION_1) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(venc->pdev, + "Unable to get VDAC_CONFIG address map\n"); + ret = -ENODEV; + goto unmap_venc_io; + } + + if (!request_mem_region(res->start, + resource_size(res), "venc")) { + dev_err(venc->pdev, + "Unable to reserve VDAC_CONFIG MMIO region\n"); + ret = -ENODEV; + goto unmap_venc_io; + } + + venc->vdaccfg_reg = ioremap_nocache(res->start, + resource_size(res)); + if (!venc->vdaccfg_reg) { + dev_err(venc->pdev, + "Unable to map VDAC_CONFIG IO space\n"); + ret = -ENODEV; + goto release_vdaccfg_mem_region; + } + } spin_lock_init(&venc->lock); platform_set_drvdata(pdev, venc); dev_notice(venc->pdev, "VENC sub device probe success\n"); return 0; +release_vdaccfg_mem_region: + release_mem_region(res->start, resource_size(res)); +unmap_venc_io: + iounmap(venc->venc_base); release_venc_mem_region: res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); @@ -529,6 +681,11 @@ static int venc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap((void *)venc->venc_base); release_mem_region(res->start, resource_size(res)); + if (venc->pdata->venc_type != VPBE_VERSION_1) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + iounmap((void *)venc->vdaccfg_reg); + release_mem_region(res->start, resource_size(res)); + } kfree(venc); return 0; @@ -543,23 +700,7 @@ static struct platform_driver venc_driver = { }, }; -static int venc_init(void) -{ - if (platform_driver_register(&venc_driver)) { - printk(KERN_ERR "Unable to register venc driver\n"); - return -ENODEV; - } - return 0; -} - -static void venc_exit(void) -{ - platform_driver_unregister(&venc_driver); - return; -} - -module_init(venc_init); -module_exit(venc_exit); +module_platform_driver(venc_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VPBE VENC Driver"); diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 5b38fc93ff28..20cf271a774b 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -2076,20 +2076,4 @@ static struct platform_driver vpfe_driver = { .remove = __devexit_p(vpfe_remove), }; -static __init int vpfe_init(void) -{ - printk(KERN_NOTICE "vpfe_init\n"); - /* Register driver to the kernel */ - return platform_driver_register(&vpfe_driver); -} - -/* - * vpfe_cleanup : This function un-registers device driver - */ -static void vpfe_cleanup(void) -{ - platform_driver_unregister(&vpfe_driver); -} - -module_init(vpfe_init); -module_exit(vpfe_cleanup); +module_platform_driver(vpfe_driver); diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 49e4deb50043..6504e40a31dd 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -2177,6 +2177,12 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } + err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); + if (err) { + v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); + return err; + } + k = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { @@ -2246,12 +2252,6 @@ static __init int vpif_probe(struct platform_device *pdev) goto probe_out; } - err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); - if (err) { - v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - goto probe_subdev_out; - } - for (i = 0; i < subdev_count; i++) { subdevdata = &config->subdev_info[i]; vpif_obj.sd[i] = @@ -2281,7 +2281,6 @@ probe_subdev_out: j = VPIF_CAPTURE_MAX_DEVICES; probe_out: - v4l2_device_unregister(&vpif_obj.v4l2_dev); for (k = 0; k < j; k++) { /* Get the pointer to the channel object */ ch = vpif_obj.dev[k]; @@ -2303,6 +2302,7 @@ vpif_int_err: if (res) i = res->end; } + v4l2_device_unregister(&vpif_obj.v4l2_dev); return err; } diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index cff0768afbf5..e2a7b77c39c7 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -193,7 +193,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) urb->dev = dev->udev; urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); + urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = dev->adev.transfer_buffer[i]; urb->interval = 1; diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 93807dcf944e..4561cd89938d 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -336,6 +336,23 @@ static struct em28xx_reg_seq pctv_460e[] = { { -1, -1, -1, -1}, }; +#if 0 +static struct em28xx_reg_seq hauppauge_930c_gpio[] = { + {EM2874_R80_GPIO, 0x6f, 0xff, 10}, + {EM2874_R80_GPIO, 0x4f, 0xff, 10}, /* xc5000 reset */ + {EM2874_R80_GPIO, 0x6f, 0xff, 10}, + {EM2874_R80_GPIO, 0x4f, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq hauppauge_930c_digital[] = { + {EM2874_R80_GPIO, 0xf6, 0xff, 10}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 10}, + { -1, -1, -1, -1}, +}; +#endif + /* * Board definitions */ @@ -839,6 +856,10 @@ struct em28xx_board em28xx_boards[] = { [EM2870_BOARD_KWORLD_355U] = { .name = "Kworld 355 U DVB-T", .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, + .tuner_gpio = default_tuner_gpio, + .has_dvb = 1, + .dvb_gpio = default_digital, }, [EM2870_BOARD_PINNACLE_PCTV_DVB] = { .name = "Pinnacle PCTV DVB-T", @@ -887,6 +908,37 @@ struct em28xx_board em28xx_boards[] = { .tuner_addr = 0x41, .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ .tuner_gpio = terratec_h5_gpio, +#else + .tuner_type = TUNER_ABSENT, +#endif + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, + [EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = { + .name = "Hauppauge WinTV HVR 930C", + .has_dvb = 1, +#if 0 /* FIXME: Add analog support */ + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x41, + .dvb_gpio = hauppauge_930c_digital, + .tuner_gpio = hauppauge_930c_gpio, +#else + .tuner_type = TUNER_ABSENT, +#endif + .ir_codes = RC_MAP_HAUPPAUGE, + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, + [EM2884_BOARD_CINERGY_HTC_STICK] = { + .name = "Terratec Cinergy HTC Stick", + .has_dvb = 1, +#if 0 + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x41, + .dvb_gpio = terratec_h5_digital, /* FIXME: probably wrong */ + .tuner_gpio = terratec_h5_gpio, #endif .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | EM28XX_I2C_CLK_WAIT_ENABLE | @@ -1127,7 +1179,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Terratec Cinergy 200 USB", .is_em2800 = 1, .has_ir_i2c = 1, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tuner_type = TUNER_LG_TALN, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_SAA711X, .input = { { @@ -1218,7 +1270,7 @@ struct em28xx_board em28xx_boards[] = { }, [EM2820_BOARD_PINNACLE_DVC_90] = { .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker " - "/ Kworld DVD Maker 2", + "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U", .tuner_type = TUNER_ABSENT, /* capture only board */ .decoder = EM28XX_SAA711X, .input = { { @@ -1840,6 +1892,22 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, }, + /* eb1a:5006 Honestech VIDBOX NW03 + * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */ + [EM2860_BOARD_HT_VIDBOX_NW03] = { + .name = "Honestech Vidbox NW03", + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, /* S-VIDEO needs confirming */ + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1899,6 +1967,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, { USB_DEVICE(0xeb1a, 0xe357), .driver_info = EM2870_BOARD_KWORLD_355U }, + { USB_DEVICE(0xeb1a, 0xe359), + .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0x1b80, 0xe302), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ { USB_DEVICE(0x1b80, 0xe304), @@ -1914,17 +1984,23 @@ struct usb_device_id em28xx_id_table[] = { { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0043), + .driver_info = EM2870_BOARD_TERRATEC_XS }, + { USB_DEVICE(0x0ccd, 0x008e), /* Cinergy HTC USB XS Rev. 1 */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x00ac), /* Cinergy HTC USB XS Rev. 2 */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, + { USB_DEVICE(0x0ccd, 0x10a2), /* H5 Rev. 1 */ .driver_info = EM2884_BOARD_TERRATEC_H5 }, - { USB_DEVICE(0x0ccd, 0x10a2), /* Rev. 1 */ + { USB_DEVICE(0x0ccd, 0x10ad), /* H5 Rev. 2 */ .driver_info = EM2884_BOARD_TERRATEC_H5 }, - { USB_DEVICE(0x0ccd, 0x10ad), /* Rev. 2 */ - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, { USB_DEVICE(0x0ccd, 0x0084), .driver_info = EM2860_BOARD_TERRATEC_AV350 }, { USB_DEVICE(0x0ccd, 0x0096), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x0ccd, 0x10AF), .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, + { USB_DEVICE(0x0ccd, 0x00b2), + .driver_info = EM2884_BOARD_CINERGY_HTC_STICK }, { USB_DEVICE(0x0fd9, 0x0033), .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, { USB_DEVICE(0x185b, 0x2870), @@ -1963,6 +2039,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, { USB_DEVICE(0x0413, 0x6023), .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, + { USB_DEVICE(0x093b, 0xa003), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x093b, 0xa005), .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, { USB_DEVICE(0x04bb, 0x0515), @@ -1975,6 +2053,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28174_BOARD_PCTV_290E }, { USB_DEVICE(0x2013, 0x024c), .driver_info = EM28174_BOARD_PCTV_460E }, + { USB_DEVICE(0x2040, 0x1605), + .driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C }, + { USB_DEVICE(0xeb1a, 0x5006), + .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, + { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ + .driver_info = EM2860_BOARD_EASYCAP }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -2028,10 +2112,10 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg) int rc = 0; struct em28xx *dev = ptr; - if (dev->tuner_type != TUNER_XC2028) + if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000) return 0; - if (command != XC2028_TUNER_RESET) + if (command != XC2028_TUNER_RESET && command != XC5000_TUNER_RESET) return 0; rc = em28xx_gpio_set(dev, dev->board.tuner_gpio); @@ -2203,7 +2287,8 @@ void em28xx_pre_card_setup(struct em28xx *dev) /* Set the initial XCLK and I2C clock values based on the board definition */ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); + if (!dev->board.is_em2800) + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); msleep(50); /* request some modules */ @@ -2832,11 +2917,10 @@ void em28xx_release_resources(struct em28xx *dev) * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ -static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, +static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, struct usb_interface *interface, int minor) { - struct em28xx *dev = *devhandle; int retval; dev->udev = udev; @@ -2931,7 +3015,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (!dev->board.is_em2800) { /* Resets I2C speed */ - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); + retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { em28xx_errdev("%s: em28xx_write_reg failed!" " retval [%d]\n", @@ -3031,12 +3115,11 @@ unregister_dev: static int em28xx_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { - const struct usb_endpoint_descriptor *endpoint; struct usb_device *udev; struct em28xx *dev = NULL; int retval; - bool is_audio_only = false, has_audio = false; - int i, nr, isoc_pipe; + bool has_audio = false, has_video = false, has_dvb = false; + int i, nr; const int ifnum = interface->altsetting[0].desc.bInterfaceNumber; char *speed; char descr[255] = ""; @@ -3068,54 +3151,65 @@ static int em28xx_usb_probe(struct usb_interface *interface, goto err; } + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + em28xx_err(DRIVER_NAME ": out of memory!\n"); + retval = -ENOMEM; + goto err; + } + + /* compute alternate max packet sizes */ + dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) * + interface->num_altsetting, GFP_KERNEL); + if (dev->alt_max_pkt_size == NULL) { + em28xx_errdev("out of memory!\n"); + kfree(dev); + retval = -ENOMEM; + goto err; + } + /* Get endpoints */ for (i = 0; i < interface->num_altsetting; i++) { int ep; for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - e = &interface->altsetting[i].endpoint[ep]; - - if (e->desc.bEndpointAddress == 0x83) - has_audio = true; + const struct usb_endpoint_descriptor *e; + int sizedescr, size; + + e = &interface->altsetting[i].endpoint[ep].desc; + + sizedescr = le16_to_cpu(e->wMaxPacketSize); + size = sizedescr & 0x7ff; + + if (udev->speed == USB_SPEED_HIGH) + size = size * hb_mult(sizedescr); + + if (usb_endpoint_xfer_isoc(e) && + usb_endpoint_dir_in(e)) { + switch (e->bEndpointAddress) { + case EM28XX_EP_AUDIO: + has_audio = true; + break; + case EM28XX_EP_ANALOG: + has_video = true; + dev->alt_max_pkt_size[i] = size; + break; + case EM28XX_EP_DIGITAL: + has_dvb = true; + if (size > dev->dvb_max_pkt_size) { + dev->dvb_max_pkt_size = size; + dev->dvb_alt = i; + } + break; + } + } } } - endpoint = &interface->cur_altsetting->endpoint[0].desc; - - /* check if the device has the iso in endpoint at the correct place */ - if (usb_endpoint_xfer_isoc(endpoint) - && - (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) { - /* It's a newer em2874/em2875 device */ - isoc_pipe = 0; - } else { - int check_interface = 1; - isoc_pipe = 1; - endpoint = &interface->cur_altsetting->endpoint[1].desc; - if (!usb_endpoint_xfer_isoc(endpoint)) - check_interface = 0; - - if (usb_endpoint_dir_out(endpoint)) - check_interface = 0; - - if (!check_interface) { - if (has_audio) { - is_audio_only = true; - } else { - em28xx_err(DRIVER_NAME " video device (%04x:%04x): " - "interface %i, class %i found.\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - em28xx_err(DRIVER_NAME " This is an anciliary " - "interface not used by the driver\n"); - - retval = -ENODEV; - goto err; - } - } + if (!(has_audio || has_video || has_dvb)) { + retval = -ENODEV; + goto err_free; } switch (udev->speed) { @@ -3141,6 +3235,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, strlcat(descr, " ", sizeof(descr)); strlcat(descr, udev->product, sizeof(descr)); } + if (*descr) strlcat(descr, " ", sizeof(descr)); @@ -3157,6 +3252,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, printk(KERN_INFO DRIVER_NAME ": Audio Vendor Class interface %i found\n", ifnum); + if (has_video) + printk(KERN_INFO DRIVER_NAME + ": Video interface %i found\n", + ifnum); + if (has_dvb) + printk(KERN_INFO DRIVER_NAME + ": DVB interface %i found\n", + ifnum); /* * Make sure we have 480 Mbps of bandwidth, otherwise things like @@ -3168,22 +3271,14 @@ static int em28xx_usb_probe(struct usb_interface *interface, printk(DRIVER_NAME ": Device must be connected to a high-speed" " USB 2.0 port.\n"); retval = -ENODEV; - goto err; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - em28xx_err(DRIVER_NAME ": out of memory!\n"); - retval = -ENOMEM; - goto err; + goto err_free; } snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr); dev->devno = nr; dev->model = id->driver_info; dev->alt = -1; - dev->is_audio_only = is_audio_only; + dev->is_audio_only = has_audio && !(has_video || has_dvb); dev->has_alsa_audio = has_audio; dev->audio_ifnum = ifnum; @@ -3196,26 +3291,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } } - /* compute alternate max packet sizes */ dev->num_alt = interface->num_altsetting; - dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); - - if (dev->alt_max_pkt_size == NULL) { - em28xx_errdev("out of memory!\n"); - kfree(dev); - retval = -ENOMEM; - goto err; - } - - for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); - unsigned int size = tmp & 0x7ff; - - if (udev->speed == USB_SPEED_HIGH) - size = size * hb_mult(tmp); - - dev->alt_max_pkt_size[i] = size; - } if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) dev->model = card[nr]; @@ -3226,12 +3302,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate device struct */ mutex_init(&dev->lock); mutex_lock(&dev->lock); - retval = em28xx_init_dev(&dev, udev, interface, nr); + retval = em28xx_init_dev(dev, udev, interface, nr); if (retval) { - mutex_unlock(&dev->lock); - kfree(dev->alt_max_pkt_size); - kfree(dev); - goto err; + goto unlock_and_free; } request_modules(dev); @@ -3250,6 +3323,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, return 0; +unlock_and_free: + mutex_unlock(&dev->lock); + +err_free: + kfree(dev->alt_max_pkt_size); + kfree(dev); + err: clear_bit(nr, &em28xx_devused); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 804a4ab47ac6..0aacc96f9a23 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -568,7 +568,7 @@ int em28xx_audio_setup(struct em28xx *dev) em28xx_warn("AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ - if ((vid == 0xffffffff) && (feat == 0x6a90)) + if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) dev->audio_mode.ac97 = EM28XX_AC97_EM202; else if ((vid >> 8) == 0x838476) dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL; @@ -1070,7 +1070,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, should also be using 'desc.bInterval' */ pipe = usb_rcvisocpipe(dev->udev, - dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84); + dev->mode == EM28XX_ANALOG_MODE ? + EM28XX_EP_ANALOG : EM28XX_EP_DIGITAL); usb_fill_int_urb(urb, dev->udev, pipe, dev->isoc_ctl.transfer_buffer[i], sb_size, @@ -1108,62 +1109,6 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, } EXPORT_SYMBOL_GPL(em28xx_init_isoc); -/* Determine the packet size for the DVB stream for the given device - (underlying value programmed into the eeprom) */ -int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev) -{ - unsigned int chip_cfg2; - unsigned int packet_size; - - switch (dev->chip_id) { - case CHIP_ID_EM2710: - case CHIP_ID_EM2750: - case CHIP_ID_EM2800: - case CHIP_ID_EM2820: - case CHIP_ID_EM2840: - case CHIP_ID_EM2860: - /* No DVB support */ - return -EINVAL; - case CHIP_ID_EM2870: - case CHIP_ID_EM2883: - /* TS max packet size stored in bits 1-0 of R01 */ - chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2); - switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) { - case EM28XX_CHIPCFG2_TS_PACKETSIZE_188: - packet_size = 188; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_376: - packet_size = 376; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_564: - packet_size = 564; - break; - case EM28XX_CHIPCFG2_TS_PACKETSIZE_752: - packet_size = 752; - break; - } - break; - case CHIP_ID_EM2874: - /* - * FIXME: for now assumes 564 like it was before, but the - * em2874 code should be added to return the proper value - */ - packet_size = 564; - break; - case CHIP_ID_EM2884: - case CHIP_ID_EM28174: - default: - /* - * FIXME: same as em2874. 564 was enough for 22 Mbit DVB-T - * but not enough for 44 Mbit DVB-C. - */ - packet_size = 752; - } - - return packet_size; -} -EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize); - /* * em28xx_wake_i2c() * configure i2c attached devices diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index cef7a2d409cb..9449423098e0 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -44,6 +44,7 @@ #include "drxk.h" #include "tda10071.h" #include "a8293.h" +#include "qt1010.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); @@ -163,12 +164,12 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) struct em28xx *dev = dvb->adapter.priv; int max_dvb_packet_size; - usb_set_interface(dev->udev, 0, 1); + usb_set_interface(dev->udev, 0, dev->dvb_alt); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; - max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev); + max_dvb_packet_size = dev->dvb_max_pkt_size; if (max_dvb_packet_size < 0) return max_dvb_packet_size; dprintk(1, "Using %d buffers each with %d bytes\n", @@ -302,10 +303,12 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = { }; static struct drxd_config em28xx_drxd = { - .index = 0, .demod_address = 0x70, .demod_revision = 0xa2, - .demoda_address = 0x00, .pll_address = 0x00, - .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1, - .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000, + .demod_address = 0x70, + .demod_revision = 0xa2, + .pll_type = DRXD_PLL_NONE, + .clock = 12000, + .insert_rs_byte = 1, + .IF = 42800000, .disable_i2c_gate_ctrl = 1, }; @@ -316,6 +319,14 @@ struct drxk_config terratec_h5_drxk = { .microcode_name = "dvb-usb-terratec-h5-drxk.fw", }; +struct drxk_config hauppauge_930c_drxk = { + .adr = 0x29, + .single_master = 1, + .no_i2c_bridge = 1, + .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw", + .chunk_size = 56, +}; + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct em28xx_dvb *dvb = fe->sec_priv; @@ -334,6 +345,73 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) return status; } +static void hauppauge_hvr930c_init(struct em28xx *dev) +{ + int i; + + struct em28xx_reg_seq hauppauge_hvr930c_init[] = { + {EM2874_R80_GPIO, 0xff, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xfb, 0xff, 0x32}, + {EM2874_R80_GPIO, 0xff, 0xff, 0xb8}, + { -1, -1, -1, -1}, + }; + struct em28xx_reg_seq hauppauge_hvr930c_end[] = { + {EM2874_R80_GPIO, 0xef, 0xff, 0x01}, + {EM2874_R80_GPIO, 0xaf, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x76}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x01}, + {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x40}, + + {EM2874_R80_GPIO, 0xcf, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x65}, + {EM2874_R80_GPIO, 0xcf, 0xff, 0x0b}, + {EM2874_R80_GPIO, 0xef, 0xff, 0x65}, + + { -1, -1, -1, -1}, + }; + + struct { + unsigned char r[4]; + int len; + } regs[] = { + {{ 0x06, 0x02, 0x00, 0x31 }, 4}, + {{ 0x01, 0x02 }, 2}, + {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0xff, 0xaf }, 4}, + {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0x73, 0xaf }, 4}, + {{ 0x04, 0x00 }, 2}, + {{ 0x00, 0x04 }, 2}, + {{ 0x00, 0x04, 0x00, 0x0a }, 4}, + {{ 0x04, 0x14 }, 2}, + {{ 0x04, 0x14, 0x00, 0x00 }, 4}, + }; + + em28xx_gpio_set(dev, hauppauge_hvr930c_init); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + msleep(10); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); + msleep(10); + + dev->i2c_client.addr = 0x82 >> 1; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + em28xx_gpio_set(dev, hauppauge_hvr930c_end); + + msleep(100); + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); + msleep(30); + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); + msleep(10); + +} + static void terratec_h5_init(struct em28xx *dev) { int i; @@ -425,13 +503,6 @@ static struct tda10023_config em28xx_tda10023_config = { static struct cxd2820r_config em28xx_cxd2820r_config = { .i2c_address = (0xd8 >> 1), .ts_mode = CXD2820R_TS_SERIAL, - .if_dvbt_6 = 3300, - .if_dvbt_7 = 3500, - .if_dvbt_8 = 4000, - .if_dvbt2_6 = 3300, - .if_dvbt2_7 = 3500, - .if_dvbt2_8 = 4000, - .if_dvbc = 5000, /* enable LNA for DVB-T2 and DVB-C */ .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L, @@ -456,6 +527,17 @@ static const struct a8293_config em28xx_a8293_config = { .i2c_addr = 0x08, /* (0x10 >> 1) */ }; +static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = { + .demod_address = (0x1e >> 1), + .disable_i2c_gate_ctrl = 1, + .no_tuner = 1, + .parallel_ts = 1, +}; +static struct qt1010_config em28xx_qt1010_config = { + .i2c_address = 0x62 + +}; + /* ------------------------------------------------------------------ */ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) @@ -708,6 +790,14 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2870_BOARD_KWORLD_355U: + dvb->fe[0] = dvb_attach(zl10353_attach, + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap); + if (dvb->fe[0] != NULL) + dvb_attach(qt1010_attach, dvb->fe[0], + &dev->i2c_adap, &em28xx_qt1010_config); + break; case EM2883_BOARD_KWORLD_HYBRID_330U: case EM2882_BOARD_EVGA_INDTUBE: dvb->fe[0] = dvb_attach(s5h1409_attach, @@ -761,50 +851,72 @@ static int em28xx_dvb_init(struct em28xx *dev) &dev->i2c_adap, &kworld_a340_config); break; case EM28174_BOARD_PCTV_290E: - /* MFE - * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */ - /* FE 0 */ dvb->fe[0] = dvb_attach(cxd2820r_attach, - &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); + &em28xx_cxd2820r_config, + &dev->i2c_adap, + NULL); if (dvb->fe[0]) { /* FE 0 attach tuner */ - if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { + if (!dvb_attach(tda18271_attach, + dvb->fe[0], + 0x60, + &dev->i2c_adap, + &em28xx_cxd2820r_tda18271_config)) { + dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; } - /* FE 1. This dvb_attach() cannot fail. */ - dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL, - dvb->fe[0]); - dvb->fe[1]->id = 1; - /* FE 1 attach tuner */ - if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, - &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { - dvb_frontend_detach(dvb->fe[1]); - /* leave FE 0 still active */ - } + } + break; + case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: + { + struct xc5000_config cfg; + hauppauge_hvr930c_init(dev); + + dvb->fe[0] = dvb_attach(drxk_attach, + &hauppauge_930c_drxk, &dev->i2c_adap); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + /* FIXME: do we need a pll semaphore? */ + dvb->fe[0]->sec_priv = dvb; + sema_init(&dvb->pll_mutex, 1); + dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl; + dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; - mfe_shared = 1; + /* Attach xc5000 */ + memset(&cfg, 0, sizeof(cfg)); + cfg.i2c_address = 0x61; + cfg.if_khz = 4000; + + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); + if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap, + &cfg)) { + result = -EINVAL; + goto out_free; } + if (dvb->fe[0]->ops.i2c_gate_ctrl) + dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); + break; + } case EM2884_BOARD_TERRATEC_H5: + case EM2884_BOARD_CINERGY_HTC_STICK: terratec_h5_init(dev); - dvb->dont_attach_fe1 = 1; - - dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap, &dvb->fe[1]); + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; } - /* FIXME: do we need a pll semaphore? */ dvb->fe[0]->sec_priv = dvb; sema_init(&dvb->pll_mutex, 1); dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl; dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl; - dvb->fe[1]->id = 1; /* Attach tda18271 to DVB-C frontend */ if (dvb->fe[0]->ops.i2c_gate_ctrl) @@ -816,12 +928,6 @@ static int em28xx_dvb_init(struct em28xx *dev) if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); - /* Hack - needed by drxk/tda18271c2dd */ - dvb->fe[1]->tuner_priv = dvb->fe[0]->tuner_priv; - memcpy(&dvb->fe[1]->ops.tuner_ops, - &dvb->fe[0]->ops.tuner_ops, - sizeof(dvb->fe[0]->ops.tuner_ops)); - break; case EM28174_BOARD_PCTV_460E: /* attach demod */ @@ -845,6 +951,8 @@ static int em28xx_dvb_init(struct em28xx *dev) } /* define general-purpose callback pointer */ dvb->fe[0]->callback = em28xx_tuner_callback; + if (dvb->fe[1]) + dvb->fe[1]->callback = em28xx_tuner_callback; /* register everything */ result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 679da4804281..2630b265b0e8 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -306,7 +306,8 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir) poll_result.rc_data[0], poll_result.toggle_bit); - if (ir->dev->chip_id == CHIP_ID_EM2874) + if (ir->dev->chip_id == CHIP_ID_EM2874 || + ir->dev->chip_id == CHIP_ID_EM2884) /* The em2874 clears the readcount field every time the register is read. The em2860/2880 datasheet says that it is supposed to clear the readcount, but it doesn't. So with @@ -371,13 +372,15 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) case CHIP_ID_EM2883: ir->get_key = default_polling_getkey; break; + case CHIP_ID_EM2884: case CHIP_ID_EM2874: case CHIP_ID_EM28174: ir->get_key = em2874_polling_getkey; em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); break; default: - printk("Unrecognized em28xx chip id: IR not supported\n"); + printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n", + dev->chip_id); rc = -EINVAL; } diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index 66f792361b97..2f6268505726 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -12,6 +12,11 @@ #define EM_GPO_2 (1 << 2) #define EM_GPO_3 (1 << 3) +/* em28xx endpoints */ +#define EM28XX_EP_ANALOG 0x82 +#define EM28XX_EP_AUDIO 0x83 +#define EM28XX_EP_DIGITAL 0x84 + /* em2800 registers */ #define EM2800_R08_AUDIOSRC 0x08 diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 9b4557a2f6d0..613300b51a9e 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1070,6 +1070,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, /* the em2800 can only scale down to 50% */ height = height > (3 * maxh / 4) ? maxh : maxh / 2; width = width > (3 * maxw / 4) ? maxw : maxw / 2; + /* MaxPacketSize for em2800 is too small to capture at full resolution + * use half of maxw as the scaler can only scale to 50% */ + if (width == maxw && height == maxh) + width /= 2; } else { /* width must even because of the YUYV format height must be even because of interlacing */ @@ -2503,6 +2507,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) { u8 val; int ret; + unsigned int maxw; printk(KERN_INFO "%s: v4l2 driver version %s\n", dev->name, EM28XX_VERSION); @@ -2515,8 +2520,15 @@ int em28xx_register_analog_devices(struct em28xx *dev) /* Analog specific initialization */ dev->format = &format[0]; + + maxw = norm_maxw(dev); + /* MaxPacketSize for em2800 is too small to capture at full resolution + * use half of maxw as the scaler can only scale to 50% */ + if (dev->board.is_em2800) + maxw /= 2; + em28xx_set_video_format(dev, format[0].fourcc, - norm_maxw(dev), norm_maxh(dev)); + maxw, norm_maxh(dev)); video_mux(dev, dev->ctl_input); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 2a2cb7ed0014..22e252bcc41e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -38,6 +38,7 @@ #include <media/videobuf-dvb.h> #endif #include "tuner-xc2028.h" +#include "xc5000.h" #include "em28xx-reg.h" /* Boards supported by driver */ @@ -121,6 +122,9 @@ #define EM28174_BOARD_PCTV_290E 78 #define EM2884_BOARD_TERRATEC_H5 79 #define EM28174_BOARD_PCTV_460E 80 +#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 +#define EM2884_BOARD_CINERGY_HTC_STICK 82 +#define EM2860_BOARD_HT_VIDBOX_NW03 83 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -594,6 +598,8 @@ struct em28xx { int max_pkt_size; /* max packet size of isoc transaction */ int num_alt; /* Number of alternative settings */ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ + int dvb_alt; /* alternate for DVB */ + unsigned int dvb_max_pkt_size; /* wMaxPacketSize for DVB */ struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */ @@ -825,7 +831,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev) if (dev->board.is_webcam) return dev->sensor_xres; - if (dev->board.max_range_640_480 || dev->board.is_em2800) + if (dev->board.max_range_640_480) return 640; return 720; diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 40f214ab924f..5539f09440ac 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -76,8 +76,8 @@ MODULE_PARM_DESC(video_nr, "\none and for every other camera." "\n"); -static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = - ET61X251_FORCE_MUNMAP}; +static bool force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] = + ET61X251_FORCE_MUNMAP}; module_param_array(force_munmap, bool, NULL, 0444); MODULE_PARM_DESC(force_munmap, "\n<0|1[,...]> Force the application to unmap previously" diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c index 27cb197d0bd6..27e3e0c0b219 100644 --- a/drivers/media/video/fsl-viu.c +++ b/drivers/media/video/fsl-viu.c @@ -1661,18 +1661,7 @@ static struct platform_driver viu_of_platform_driver = { }, }; -static int __init viu_init(void) -{ - return platform_driver_register(&viu_of_platform_driver); -} - -static void __exit viu_exit(void) -{ - platform_driver_unregister(&viu_of_platform_driver); -} - -module_init(viu_init); -module_exit(viu_exit); +module_platform_driver(viu_of_platform_driver); MODULE_DESCRIPTION("Freescale Video-In(VIU)"); MODULE_AUTHOR("Hongjun Chen"); diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 103af3fe5aa0..dfe268bfa4f8 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -77,6 +77,16 @@ config USB_GSPCA_JEILINJ To compile this driver as a module, choose M here: the module will be called gspca_jeilinj. +config USB_GSPCA_JL2005BCD + tristate "JL2005B/C/D USB V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based the + JL2005B, JL2005C, or JL2005D chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_jl2005bcd. + config USB_GSPCA_KINECT tristate "Kinect sensor device USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index f345f494d0f3..79ebe46e1ad7 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o +obj-$(CONFIG_USB_GSPCA_JL2005BCD) += gspca_jl2005bcd.o obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o @@ -49,6 +50,7 @@ gspca_cpia1-objs := cpia1.o gspca_etoms-objs := etoms.o gspca_finepix-objs := finepix.o gspca_jeilinj-objs := jeilinj.o +gspca_jl2005bcd-objs := jl2005bcd.o gspca_kinect-objs := kinect.o gspca_konica-objs := konica.o gspca_mars-objs := mars.o diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c index 636627b57dc9..9769f17915c0 100644 --- a/drivers/media/video/gspca/benq.c +++ b/drivers/media/video/gspca/benq.c @@ -76,7 +76,6 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); gspca_dev->cam.no_urb_create = 1; - gspca_dev->cam.reverse_alts = 1; return 0; } @@ -135,13 +134,17 @@ static int sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { + struct usb_interface *intf; + reg_w(gspca_dev, 0x003c, 0x0003); reg_w(gspca_dev, 0x003c, 0x0004); reg_w(gspca_dev, 0x003c, 0x0005); reg_w(gspca_dev, 0x003c, 0x0006); reg_w(gspca_dev, 0x003c, 0x0007); + + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); usb_set_interface(gspca_dev->dev, gspca_dev->iface, - gspca_dev->nbalt - 1); + intf->num_altsetting - 1); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index a8f54c20e585..c84e26006fc3 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -337,7 +337,6 @@ static int sd_config(struct gspca_dev *gspca_dev, return -1; cam = &gspca_dev->cam; - gspca_dev->nbalt = 4; switch (sd->sensor) { case ID_MI1320: diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 2ca10dfec91f..ca5a2b139d0b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -633,23 +633,32 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev) u32 bandwidth; int i; + /* get the (max) image size */ i = gspca_dev->curr_mode; bandwidth = gspca_dev->cam.cam_mode[i].sizeimage; - /* if the image is compressed, estimate the mean image size */ - if (bandwidth < gspca_dev->cam.cam_mode[i].width * + /* if the image is compressed, estimate its mean size */ + if (!gspca_dev->cam.needs_full_bandwidth && + bandwidth < gspca_dev->cam.cam_mode[i].width * gspca_dev->cam.cam_mode[i].height) - bandwidth /= 3; + bandwidth = bandwidth * 3 / 8; /* 0.375 */ /* estimate the frame rate */ if (gspca_dev->sd_desc->get_streamparm) { struct v4l2_streamparm parm; - parm.parm.capture.timeperframe.denominator = 15; gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm); bandwidth *= parm.parm.capture.timeperframe.denominator; + bandwidth /= parm.parm.capture.timeperframe.numerator; } else { - bandwidth *= 15; /* 15 fps */ + + /* don't hope more than 15 fps with USB 1.1 and + * image resolution >= 640x480 */ + if (gspca_dev->width >= 640 + && gspca_dev->dev->speed == USB_SPEED_FULL) + bandwidth *= 15; /* 15 fps */ + else + bandwidth *= 30; /* 30 fps */ } PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth); @@ -667,9 +676,8 @@ struct ep_tb_s { * build the table of the endpoints * and compute the minimum bandwidth for the image transfer */ -static int build_ep_tb(struct gspca_dev *gspca_dev, +static int build_isoc_ep_tb(struct gspca_dev *gspca_dev, struct usb_interface *intf, - int xfer, struct ep_tb_s *ep_tb) { struct usb_host_endpoint *ep; @@ -687,17 +695,21 @@ static int build_ep_tb(struct gspca_dev *gspca_dev, ep_tb->bandwidth = 2000 * 2000 * 120; found = 0; for (j = 0; j < nbalt; j++) { - ep = alt_xfer(&intf->altsetting[j], xfer); + ep = alt_xfer(&intf->altsetting[j], + USB_ENDPOINT_XFER_ISOC); if (ep == NULL) continue; + if (ep->desc.bInterval == 0) { + pr_err("alt %d iso endp with 0 interval\n", j); + continue; + } psize = le16_to_cpu(ep->desc.wMaxPacketSize); - if (!gspca_dev->cam.bulk) /* isoc */ - psize = (psize & 0x07ff) * - (1 + ((psize >> 11) & 3)); - bandwidth = psize * ep->desc.bInterval * 1000; + psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + bandwidth = psize * 1000; if (gspca_dev->dev->speed == USB_SPEED_HIGH || gspca_dev->dev->speed == USB_SPEED_SUPER) bandwidth *= 8; + bandwidth /= 1 << (ep->desc.bInterval - 1); if (bandwidth <= last_bw) continue; if (bandwidth < ep_tb->bandwidth) { @@ -715,6 +727,23 @@ static int build_ep_tb(struct gspca_dev *gspca_dev, ep_tb++; } + /* + * If the camera: + * has a usb audio class interface (a built in usb mic); and + * is a usb 1 full speed device; and + * uses the max full speed iso bandwidth; and + * and has more than 1 alt setting + * then skip the highest alt setting to spare bandwidth for the mic + */ + if (gspca_dev->audio && + gspca_dev->dev->speed == USB_SPEED_FULL && + last_bw >= 1000000 && + i > 1) { + PDEBUG(D_STREAM, "dev has usb audio, skipping highest alt"); + i--; + ep_tb--; + } + /* get the requested bandwidth and start at the highest atlsetting */ bandwidth = which_bandwidth(gspca_dev); ep_tb--; @@ -790,10 +819,7 @@ static int create_urbs(struct gspca_dev *gspca_dev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - if (gspca_dev->dev->speed == USB_SPEED_LOW) - urb->interval = ep->desc.bInterval; - else - urb->interval = 1 << (ep->desc.bInterval - 1); + urb->interval = 1 << (ep->desc.bInterval - 1); urb->complete = isoc_irq; urb->number_of_packets = npkt; for (i = 0; i < npkt; i++) { @@ -848,7 +874,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_ISOC; - /* if the subdriver forced an altsetting, get the endpoint */ + /* if bulk or the subdriver forced an altsetting, get the endpoint */ if (gspca_dev->alt != 0) { gspca_dev->alt--; /* (previous version compatibility) */ ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer); @@ -863,7 +889,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* else, compute the minimum bandwidth * and build the endpoint table */ - alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb); + alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb); if (alt_idx <= 0) { pr_err("no transfer endpoint found\n"); ret = -EIO; @@ -880,7 +906,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) for (;;) { if (alt != gspca_dev->alt) { alt = gspca_dev->alt; - if (gspca_dev->nbalt > 1) { + if (intf->num_altsetting > 1) { ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, alt); @@ -2300,15 +2326,14 @@ int gspca_dev_probe2(struct usb_interface *intf, } gspca_dev->dev = dev; gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber; - gspca_dev->nbalt = intf->num_altsetting; /* check if any audio device */ - if (dev->config->desc.bNumInterfaces != 1) { + if (dev->actconfig->desc.bNumInterfaces != 1) { int i; struct usb_interface *intf2; - for (i = 0; i < dev->config->desc.bNumInterfaces; i++) { - intf2 = dev->config->interface[i]; + for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { + intf2 = dev->actconfig->interface[i]; if (intf2 != NULL && intf2->altsetting != NULL && intf2->altsetting->desc.bInterfaceClass == @@ -2389,7 +2414,7 @@ int gspca_dev_probe(struct usb_interface *intf, } /* the USB video interface must be the first one */ - if (dev->config->desc.bNumInterfaces != 1 + if (dev->actconfig->desc.bNumInterfaces != 1 && intf->cur_altsetting->desc.bInterfaceNumber != 0) return -ENODEV; diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index e444f16e1497..589009f4496f 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -69,7 +69,9 @@ struct cam { u8 bulk; /* image transfer by 0:isoc / 1:bulk */ u8 npkt; /* number of packets in an ISOC message * 0 is the default value: 32 packets */ - u8 reverse_alts; /* Alt settings are in high to low order */ + u8 needs_full_bandwidth;/* Set this flag to notify the bandwidth calc. + * code that the cam fills all image buffers to + * the max, even when using compression. */ }; struct gspca_dev; @@ -208,7 +210,6 @@ struct gspca_dev { char memory; /* memory type (V4L2_MEMORY_xxx) */ __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ - __u8 nbalt; /* number of USB alternate settings */ u8 audio; /* presence of audio device */ }; diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c new file mode 100644 index 000000000000..53f58ef367cf --- /dev/null +++ b/drivers/media/video/gspca/jl2005bcd.c @@ -0,0 +1,554 @@ +/* + * Jeilin JL2005B/C/D library + * + * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu> + * + * 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 + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "jl2005bcd" + +#include <linux/workqueue.h> +#include <linux/slab.h> +#include "gspca.h" + + +MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>"); +MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Default timeouts, in ms */ +#define JL2005C_CMD_TIMEOUT 500 +#define JL2005C_DATA_TIMEOUT 1000 + +/* Maximum transfer size to use. */ +#define JL2005C_MAX_TRANSFER 0x200 +#define FRAME_HEADER_LEN 16 + + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + unsigned char firmware_id[6]; + const struct v4l2_pix_format *cap_mode; + /* Driver stuff */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; + u8 frame_brightness; + int block_size; /* block size of camera */ + int vga; /* 1 if vga cam, 0 if cif cam */ +}; + + +/* Camera has two resolution settings. What they are depends on model. */ +static const struct v4l2_pix_format cif_mode[] = { + {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, + {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + +/* + * cam uses endpoint 0x03 to send commands, 0x84 for read commands, + * and 0x82 for bulk data transfer. + */ + +/* All commands are two bytes only */ +static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command) +{ + int retval; + + memcpy(gspca_dev->usb_buf, command, 2); + retval = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, 2, NULL, 500); + if (retval < 0) + pr_err("command write [%02x] error %d\n", + gspca_dev->usb_buf[0], retval); + return retval; +} + +/* Response to a command is one byte in usb_buf[0], only if requested. */ +static int jl2005c_read1(struct gspca_dev *gspca_dev) +{ + int retval; + + retval = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x84), + gspca_dev->usb_buf, 1, NULL, 500); + if (retval < 0) + pr_err("read command [0x%02x] error %d\n", + gspca_dev->usb_buf[0], retval); + return retval; +} + +/* Response appears in gspca_dev->usb_buf[0] */ +static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg) +{ + int retval; + + static u8 instruction[2] = {0x95, 0x00}; + /* put register to read in byte 1 */ + instruction[1] = reg; + /* Send the read request */ + retval = jl2005c_write2(gspca_dev, instruction); + if (retval < 0) + return retval; + retval = jl2005c_read1(gspca_dev); + + return retval; +} + +static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) +{ + int i; + int retval; + int frame_brightness = 0; + + static u8 instruction[2] = {0x7f, 0x01}; + + retval = jl2005c_write2(gspca_dev, instruction); + if (retval < 0) + return retval; + + i = 0; + while (i < 20 && !frame_brightness) { + /* If we tried 20 times, give up. */ + retval = jl2005c_read_reg(gspca_dev, 0x7e); + if (retval < 0) + return retval; + frame_brightness = gspca_dev->usb_buf[0]; + retval = jl2005c_read_reg(gspca_dev, 0x7d); + if (retval < 0) + return retval; + i++; + } + PDEBUG(D_FRAM, "frame_brightness is 0x%02x", gspca_dev->usb_buf[0]); + return retval; +} + +static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, + unsigned char value) +{ + int retval; + u8 instruction[2]; + + instruction[0] = reg; + instruction[1] = value; + + retval = jl2005c_write2(gspca_dev, instruction); + if (retval < 0) + return retval; + + return retval; +} + +static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + int i = 0; + int retval = -1; + unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f}; + + PDEBUG(D_PROBE, "Running jl2005c_get_firmware_id"); + /* Read the first ID byte once for warmup */ + retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]); + PDEBUG(D_PROBE, "response is %02x", gspca_dev->usb_buf[0]); + if (retval < 0) + return retval; + /* Now actually get the ID string */ + for (i = 0; i < 6; i++) { + retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]); + if (retval < 0) + return retval; + sd->firmware_id[i] = gspca_dev->usb_buf[0]; + } + PDEBUG(D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x", + sd->firmware_id[0], + sd->firmware_id[1], + sd->firmware_id[2], + sd->firmware_id[3], + sd->firmware_id[4], + sd->firmware_id[5]); + return 0; +} + +static int jl2005c_stream_start_vga_lg + (struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x05, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x18}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x52}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + +static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x06, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x1a}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x52}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + +static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x05, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x30}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x42}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + +static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + static u8 instruction[][2] = { + {0x06, 0x00}, + {0x7c, 0x00}, + {0x7d, 0x32}, + {0x02, 0x00}, + {0x01, 0x00}, + {0x04, 0x42}, + }; + + for (i = 0; i < ARRAY_SIZE(instruction); i++) { + msleep(60); + retval = jl2005c_write2(gspca_dev, instruction[i]); + if (retval < 0) + return retval; + } + msleep(60); + return retval; +} + + +static int jl2005c_stop(struct gspca_dev *gspca_dev) +{ + int retval; + + retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00); + return retval; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface the gspca usb_lock is + * used when performing the one USB control operation inside the workqueue, + * which tells the camera to close the stream. In practice the only thing + * which needs to be protected against is the usb_set_interface call that + * gspca makes during stream_off. Otherwise the camera doesn't provide any + * controls that the user could try to change. + */ +static void jl2005c_dostream(struct work_struct *work) +{ + struct sd *dev = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &dev->gspca_dev; + int bytes_left = 0; /* bytes remaining in current frame. */ + int data_len; /* size to use for the next read. */ + int header_read = 0; + unsigned char header_sig[2] = {0x4a, 0x4c}; + int act_len; + int packet_type; + int ret; + u8 *buffer; + + buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); + if (!buffer) { + pr_err("Couldn't allocate USB buffer\n"); + goto quit_stream; + } + + while (gspca_dev->present && gspca_dev->streaming) { + /* Check if this is a new frame. If so, start the frame first */ + if (!header_read) { + mutex_lock(&gspca_dev->usb_lock); + ret = jl2005c_start_new_frame(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) + goto quit_stream; + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x82), + buffer, JL2005C_MAX_TRANSFER, &act_len, + JL2005C_DATA_TIMEOUT); + PDEBUG(D_PACK, + "Got %d bytes out of %d for header", + act_len, JL2005C_MAX_TRANSFER); + if (ret < 0 || act_len < JL2005C_MAX_TRANSFER) + goto quit_stream; + /* Check whether we actually got the first blodk */ + if (memcmp(header_sig, buffer, 2) != 0) { + pr_err("First block is not the first block\n"); + goto quit_stream; + } + /* total size to fetch is byte 7, times blocksize + * of which we already got act_len */ + bytes_left = buffer[0x07] * dev->block_size - act_len; + PDEBUG(D_PACK, "bytes_left = 0x%x", bytes_left); + /* We keep the header. It has other information, too.*/ + packet_type = FIRST_PACKET; + gspca_frame_add(gspca_dev, packet_type, + buffer, act_len); + header_read = 1; + } + while (bytes_left > 0 && gspca_dev->present) { + data_len = bytes_left > JL2005C_MAX_TRANSFER ? + JL2005C_MAX_TRANSFER : bytes_left; + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x82), + buffer, data_len, &act_len, + JL2005C_DATA_TIMEOUT); + if (ret < 0 || act_len < data_len) + goto quit_stream; + PDEBUG(D_PACK, + "Got %d bytes out of %d for frame", + data_len, bytes_left); + bytes_left -= data_len; + if (bytes_left == 0) { + packet_type = LAST_PACKET; + header_read = 0; + } else + packet_type = INTER_PACKET; + gspca_frame_add(gspca_dev, packet_type, + buffer, data_len); + } + } +quit_stream: + if (gspca_dev->present) { + mutex_lock(&gspca_dev->usb_lock); + jl2005c_stop(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + kfree(buffer); +} + + + + +/* This function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam; + struct sd *sd = (struct sd *) gspca_dev; + + cam = &gspca_dev->cam; + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk_size = 64; + cam->bulk = 1; + /* For the rest, the camera needs to be detected */ + jl2005c_get_firmware_id(gspca_dev); + /* Here are some known firmware IDs + * First some JL2005B cameras + * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam + * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B + * JL2005C cameras + * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512 + * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly + * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz + * + * Based upon this scanty evidence, we can detect a CIF camera by + * testing byte 0 for 0x4x. + */ + if ((sd->firmware_id[0] & 0xf0) == 0x40) { + cam->cam_mode = cif_mode; + cam->nmodes = ARRAY_SIZE(cif_mode); + sd->block_size = 0x80; + } else { + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + sd->block_size = 0x200; + } + + INIT_WORK(&sd->work_struct, jl2005c_dostream); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +static int sd_start(struct gspca_dev *gspca_dev) +{ + + struct sd *sd = (struct sd *) gspca_dev; + sd->cap_mode = gspca_dev->cam.cam_mode; + + switch (gspca_dev->width) { + case 640: + PDEBUG(D_STREAM, "Start streaming at vga resolution"); + jl2005c_stream_start_vga_lg(gspca_dev); + break; + case 320: + PDEBUG(D_STREAM, "Start streaming at qvga resolution"); + jl2005c_stream_start_vga_small(gspca_dev); + break; + case 352: + PDEBUG(D_STREAM, "Start streaming at cif resolution"); + jl2005c_stream_start_cif_lg(gspca_dev); + break; + case 176: + PDEBUG(D_STREAM, "Start streaming at qcif resolution"); + jl2005c_stream_start_cif_small(gspca_dev); + break; + default: + pr_err("Unknown resolution specified\n"); + return -1; + } + + /* Start the workqueue function to do the streaming */ + sd->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(sd->work_thread, &sd->work_struct); + + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for sq905c_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); +} + + + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + /* .ctrls = none have been detected */ + /* .nctrls = ARRAY_SIZE(sd_ctrls), */ + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- module initialisation -- */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x0979, 0x0227)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c index b1da7f4096c8..f0c0d74dfe92 100644 --- a/drivers/media/video/gspca/konica.c +++ b/drivers/media/video/gspca/konica.c @@ -247,9 +247,6 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); gspca_dev->cam.no_urb_create = 1; - /* The highest alt setting has an isoc packetsize of 0, so we - don't want to use it */ - gspca_dev->nbalt--; sd->brightness = BRIGHTNESS_DEFAULT; sd->contrast = CONTRAST_DEFAULT; diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 9fe3816b2aa0..0c4493675438 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -27,8 +27,8 @@ /* Kernel module parameters */ int force_sensor; -static int dump_bridge; -int dump_sensor; +static bool dump_bridge; +bool dump_sensor; static const struct usb_device_id m5602_table[] = { {USB_DEVICE(0x0402, 0x5602)}, diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h index b1f0c492036a..8c672b5c8c6a 100644 --- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h +++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h @@ -106,7 +106,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int mt9m111_probe(struct sd *sd); int mt9m111_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h index 2efd607987ec..2b6a13b508f7 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov7660.h +++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h @@ -86,7 +86,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int ov7660_probe(struct sd *sd); int ov7660_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h index da9a129b739d..f7aa5bf68983 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.h +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h @@ -135,7 +135,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int ov9650_probe(struct sd *sd); int ov9650_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h index 338359596398..81a2bcb88fe3 100644 --- a/drivers/media/video/gspca/m5602/m5602_po1030.h +++ b/drivers/media/video/gspca/m5602/m5602_po1030.h @@ -147,7 +147,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int po1030_probe(struct sd *sd); int po1030_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h index 8cc7a3f6da72..8e0035e731c7 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h @@ -65,7 +65,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int s5k4aa_probe(struct sd *sd); int s5k4aa_init(struct sd *sd); diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h index 80a63a236e24..79952247b534 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h +++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h @@ -41,7 +41,7 @@ /* Kernel module parameters */ extern int force_sensor; -extern int dump_sensor; +extern bool dump_sensor; int s5k83a_probe(struct sd *sd); int s5k83a_init(struct sd *sd); diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index 5c2ea05c46b4..b0231465afae 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -263,7 +263,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode); cam->ctrls = sd->ctrls; sd->quality = QUALITY_DEF; - gspca_dev->nbalt = 9; /* use the altsetting 08 */ return 0; } diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index d4bec9321771..7167cac7359c 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -1763,8 +1763,8 @@ static int sd_config(struct gspca_dev *gspca_dev, if ((unsigned) webcam >= NWEBCAMS) webcam = 0; sd->webcam = webcam; - gspca_dev->cam.reverse_alts = 1; gspca_dev->cam.ctrls = sd->ctrls; + gspca_dev->cam.needs_full_bandwidth = 1; sd->ag_cnt = -1; /* diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 08b8ce1dee18..739e8a2a2d30 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -3348,7 +3348,6 @@ static int sd_config(struct gspca_dev *gspca_dev, case BRIDGE_W9968CF: cam->cam_mode = w9968cf_vga_mode; cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); - cam->reverse_alts = 1; break; } @@ -3684,8 +3683,8 @@ static void ov511_mode_init_regs(struct sd *sd) /* Check if we have enough bandwidth to disable compression */ fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1; needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2; - /* 1400 is a conservative estimate of the max nr of isoc packets/sec */ - if (needed > 1400 * packet_size) { + /* 1000 isoc packets/sec */ + if (needed > 1000 * packet_size) { /* Enable Y and UV quantization and compression */ reg_w(sd, R511_COMP_EN, 0x07); reg_w(sd, R511_COMP_LUT_EN, 0x03); diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c index f30060d50633..fbfa02affa13 100644 --- a/drivers/media/video/gspca/ov534_9.c +++ b/drivers/media/video/gspca/ov534_9.c @@ -71,6 +71,7 @@ struct sd { enum sensors { SENSOR_OV965x, /* ov9657 */ SENSOR_OV971x, /* ov9712 */ + SENSOR_OV562x, /* ov5621 */ NSENSORS }; @@ -207,6 +208,14 @@ static const struct v4l2_pix_format ov971x_mode[] = { } }; +static const struct v4l2_pix_format ov562x_mode[] = { + {2592, 1680, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 2592, + .sizeimage = 2592 * 1680, + .colorspace = V4L2_COLORSPACE_SRGB + } +}; + static const u8 bridge_init[][2] = { {0x88, 0xf8}, {0x89, 0xff}, @@ -830,6 +839,124 @@ static const u8 ov965x_start_2_sxga[][2] = { {0xa3, 0x41}, /* bd60 */ }; +static const u8 ov562x_init[][2] = { + {0x88, 0x20}, + {0x89, 0x0a}, + {0x8a, 0x90}, + {0x8b, 0x06}, + {0x8c, 0x01}, + {0x8d, 0x10}, + {0x1c, 0x00}, + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1c, 0x0a}, + {0x1d, 0x2e}, + {0x1d, 0x1e}, +}; + +static const u8 ov562x_init_2[][2] = { + {0x12, 0x80}, + {0x11, 0x41}, + {0x13, 0x00}, + {0x10, 0x1e}, + {0x3b, 0x07}, + {0x5b, 0x40}, + {0x39, 0x07}, + {0x53, 0x02}, + {0x54, 0x60}, + {0x04, 0x20}, + {0x27, 0x04}, + {0x3d, 0x40}, + {0x36, 0x00}, + {0xc5, 0x04}, + {0x4e, 0x00}, + {0x4f, 0x93}, + {0x50, 0x7b}, + {0xca, 0x0c}, + {0xcb, 0x0f}, + {0x39, 0x07}, + {0x4a, 0x10}, + {0x3e, 0x0a}, + {0x3d, 0x00}, + {0x0c, 0x38}, + {0x38, 0x90}, + {0x46, 0x30}, + {0x4f, 0x93}, + {0x50, 0x7b}, + {0xab, 0x00}, + {0xca, 0x0c}, + {0xcb, 0x0f}, + {0x37, 0x02}, + {0x44, 0x48}, + {0x8d, 0x44}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x32, 0x00}, + {0x38, 0x90}, + {0x53, 0x02}, + {0x54, 0x60}, + {0x12, 0x00}, + {0x17, 0x12}, + {0x18, 0xb4}, + {0x19, 0x0c}, + {0x1a, 0xf4}, + {0x03, 0x4a}, + {0x89, 0x20}, + {0x83, 0x80}, + {0xb7, 0x9d}, + {0xb6, 0x11}, + {0xb5, 0x55}, + {0xb4, 0x00}, + {0xa9, 0xf0}, + {0xa8, 0x0a}, + {0xb8, 0xf0}, + {0xb9, 0xf0}, + {0xba, 0xf0}, + {0x81, 0x07}, + {0x63, 0x44}, + {0x13, 0xc7}, + {0x14, 0x60}, + {0x33, 0x75}, + {0x2c, 0x00}, + {0x09, 0x00}, + {0x35, 0x30}, + {0x27, 0x04}, + {0x3c, 0x07}, + {0x3a, 0x0a}, + {0x3b, 0x07}, + {0x01, 0x40}, + {0x02, 0x40}, + {0x16, 0x40}, + {0x52, 0xb0}, + {0x51, 0x83}, + {0x21, 0xbb}, + {0x22, 0x10}, + {0x23, 0x03}, + {0x35, 0x38}, + {0x20, 0x90}, + {0x28, 0x30}, + {0x73, 0xe1}, + {0x6c, 0x00}, + {0x6d, 0x80}, + {0x6e, 0x00}, + {0x70, 0x04}, + {0x71, 0x00}, + {0x8d, 0x04}, + {0x64, 0x00}, + {0x65, 0x00}, + {0x66, 0x00}, + {0x67, 0x00}, + {0x68, 0x00}, + {0x69, 0x00}, + {0x6a, 0x00}, + {0x6b, 0x00}, + {0x71, 0x94}, + {0x74, 0x20}, + {0x80, 0x09}, + {0x85, 0xc0}, +}; + static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val) { struct usb_device *udev = gspca_dev->dev; @@ -1210,6 +1337,17 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x56, 0x1f); else reg_w(gspca_dev, 0x56, 0x17); + } else if ((sensor_id & 0xfff0) == 0x5620) { + sd->sensor = SENSOR_OV562x; + + gspca_dev->cam.cam_mode = ov562x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode); + + reg_w_array(gspca_dev, ov562x_init, + ARRAY_SIZE(ov562x_init)); + sccb_w_array(gspca_dev, ov562x_init_2, + ARRAY_SIZE(ov562x_init_2)); + reg_w(gspca_dev, 0xe0, 0x00); } else { err("Unknown sensor %04x", sensor_id); return -EINVAL; @@ -1222,7 +1360,7 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->sensor == SENSOR_OV971x) + if (sd->sensor == SENSOR_OV971x || sd->sensor == SENSOR_OV562x) return gspca_dev->usb_err; switch (gspca_dev->curr_mode) { case QVGA_MODE: /* 320x240 */ @@ -1409,6 +1547,7 @@ static const struct sd_desc sd_desc = { static const struct usb_device_id device_table[] = { {USB_DEVICE(0x05a9, 0x8065)}, {USB_DEVICE(0x06f8, 0x3003)}, + {USB_DEVICE(0x05a9, 0x1550)}, {} }; diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index ece8b1e82a13..3844c49f269c 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -41,14 +41,14 @@ MODULE_LICENSE("GPL"); #define PAC207_BRIGHTNESS_DEFAULT 46 #define PAC207_EXPOSURE_MIN 3 -#define PAC207_EXPOSURE_MAX 26 +#define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */ #define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ -#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */ +#define PAC207_EXPOSURE_KNEE 9 /* fps: 90 / exposure -> 9: 10 fps */ #define PAC207_GAIN_MIN 0 #define PAC207_GAIN_MAX 31 -#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */ -#define PAC207_GAIN_KNEE 31 +#define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */ +#define PAC207_GAIN_KNEE 15 #define PAC207_AUTOGAIN_DEADZONE 30 @@ -332,7 +332,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - 100, PAC207_AUTOGAIN_DEADZONE, + 90, PAC207_AUTOGAIN_DEADZONE, PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 2811195258c4..9db2b34d172c 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -1197,6 +1197,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x262a)}, {USB_DEVICE(0x093a, 0x262c)}, + {USB_DEVICE(0x145f, 0x013c)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c index 1494e1829d36..bb70092c2229 100644 --- a/drivers/media/video/gspca/se401.c +++ b/drivers/media/video/gspca/se401.c @@ -376,7 +376,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->bulk_size = BULK_SIZE; cam->bulk_nurbs = 4; cam->ctrls = sd->ctrls; - gspca_dev->nbalt = 1; /* Ignore the bogus isoc alt settings */ sd->resetlevel = 0x2d; /* Set initial resetlevel */ /* See if the camera supports brightness */ @@ -395,6 +394,14 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + gspca_dev->alt = 1; /* Ignore the bogus isoc alt settings */ + + return gspca_dev->usb_err; +} + /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -714,6 +721,7 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .dq_callback = sd_dq_callback, diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 33cabc342dcf..9e198b45c3c8 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -2048,6 +2048,7 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; + cam->needs_full_bandwidth = 1; sd->sensor = (id->driver_info >> 8) & 0xff; sd->i2c_addr = id->driver_info & 0xff; @@ -2233,6 +2234,42 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) } } +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct usb_interface *intf; + u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv; + + /* + * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth + * than our regular bandwidth calculations reserve, so we force the + * use of a specific altsetting when using the SN9C20X_I420 fmt. + */ + if (!(flags & (MODE_RAW | MODE_JPEG))) { + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + + if (intf->num_altsetting != 9) { + pr_warn("sn9c20x camera with unknown number of alt " + "settings (%d), please report!\n", + intf->num_altsetting); + gspca_dev->alt = intf->num_altsetting; + return 0; + } + + switch (gspca_dev->width) { + case 160: /* 160x120 */ + gspca_dev->alt = 2; + break; + case 320: /* 320x240 */ + gspca_dev->alt = 6; + break; + default: /* >= 640x480 */ + gspca_dev->alt = 9; + } + } + + return 0; +} + #define HW_WIN(mode, hstart, vstart) \ ((const u8 []){hstart, 0, vstart, 0, \ (mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ @@ -2473,6 +2510,7 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index ddb392dc4f2d..6a1148d7fe92 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1079,20 +1079,23 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam->npkt = 36; /* 36 packets per ISOC message */ - if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { - sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; - sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; - sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; - } - return 0; } /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; const __u8 stop = 0x09; /* Disable stream turn of LED */ + if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { + sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; + sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; + sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; + if (sd->ctrls[EXPOSURE].val > COARSE_EXPOSURE_MAX) + sd->ctrls[EXPOSURE].val = COARSE_EXPOSURE_DEF; + } + reg_w(gspca_dev, 0x01, &stop, 1); return 0; diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index afa3186b8038..0c9e6ddabd2c 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1235,7 +1235,7 @@ static const u8 po2030n_sensor_param1[][8] = { {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */ {0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10}, - {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10}, + {0xd1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x40, 0x10}, /* RGBG gains */ /*param2*/ {0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10}, @@ -1779,10 +1779,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->ag_cnt = -1; sd->quality = QUALITY_DEF; - /* if USB 1.1, let some bandwidth for the audio device */ - if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) - gspca_dev->nbalt--; - INIT_WORK(&sd->work, qual_upd); return 0; @@ -2063,6 +2059,16 @@ static void setredblue(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor == SENSOR_PO2030N) { + u8 rg1b[] = /* red green1 blue (no g2) */ + {0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10}; + + /* 0x40 = normal value = gain x 1 */ + rg1b[3] = sd->ctrls[RED].val * 2; + rg1b[5] = sd->ctrls[BLUE].val * 2; + i2c_w8(gspca_dev, rg1b); + return; + } reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val); /* reg_w1(gspca_dev, 0x07, 32); */ reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val); @@ -2397,7 +2403,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x17, reg17); reg01 &= ~S_PWR_DN; /* sensor power on */ reg_w1(gspca_dev, 0x01, reg01); - reg01 &= ~SYS_SEL_48M; + reg01 &= ~SCL_SEL_OD; /* remove open-drain mode */ reg_w1(gspca_dev, 0x01, reg01); switch (sd->sensor) { diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index 259a0c73c664..4a5f209ce719 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/drivers/media/video/gspca/spca561.c @@ -451,7 +451,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ + cam->needs_full_bandwidth = 1; sd->chip_revision = id->driver_info; if (sd->chip_revision == Rev012A) { diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 0ab425fbea9a..91d99b4cc57b 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -36,8 +36,8 @@ MODULE_AUTHOR("Erik Andrén"); MODULE_DESCRIPTION("STV06XX USB Camera Driver"); MODULE_LICENSE("GPL"); -static int dump_bridge; -static int dump_sensor; +static bool dump_bridge; +static bool dump_sensor; int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) { @@ -304,7 +304,7 @@ static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); @@ -317,7 +317,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) struct usb_host_interface *alt; struct sd *sd = (struct sd *) gspca_dev; - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; if (packet_size <= min_packet_size) diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c index ea44deb66af4..9b9f85a8e60e 100644 --- a/drivers/media/video/gspca/t613.c +++ b/drivers/media/video/gspca/t613.c @@ -30,6 +30,7 @@ #define MODULE_NAME "t613" +#include <linux/input.h> #include <linux/slab.h> #include "gspca.h" @@ -57,6 +58,7 @@ struct sd { u8 effect; u8 sensor; + u8 button_pressed; }; enum sensors { SENSOR_OM6802, @@ -1095,15 +1097,35 @@ static void sd_stopN(struct gspca_dev *gspca_dev) msleep(20); reg_w(gspca_dev, 0x0309); } +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* If the last button state is pressed, release it now! */ + if (sd->button_pressed) { + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + sd->button_pressed = 0; + } +#endif } static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* isoc packet */ int len) /* iso packet length */ { + struct sd *sd = (struct sd *) gspca_dev; int pkt_type; if (data[0] == 0x5a) { +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + if (len > 20) { + u8 state = (data[20] & 0x80) ? 1 : 0; + if (sd->button_pressed != state) { + input_report_key(gspca_dev->input_dev, + KEY_CAMERA, state); + input_sync(gspca_dev->input_dev); + sd->button_pressed = state; + } + } +#endif /* Control Packet, after this came the header again, * but extra bytes came in the packet before this, * sometimes an EOF arrives, sometimes not... */ @@ -1410,6 +1432,9 @@ static const struct sd_desc sd_desc = { .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif }; /* -- module initialisation -- */ diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c index b2695b1dc603..444d3c5b9079 100644 --- a/drivers/media/video/gspca/topro.c +++ b/drivers/media/video/gspca/topro.c @@ -3946,7 +3946,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev) /* 640x480 * 30 fps does not work */ if (i == 6 /* if 30 fps */ && gspca_dev->width == 640) - i = 0x86; /* 15 fps */ + i = 0x05; /* 15 fps */ } else { for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) { if (sd->framerate >= rates_6810[i]) diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c index d12ea1518ace..911152e169d6 100644 --- a/drivers/media/video/gspca/vicam.c +++ b/drivers/media/video/gspca/vicam.c @@ -324,7 +324,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev) dev->work_thread = NULL; mutex_lock(&gspca_dev->usb_lock); - vicam_set_camera_power(gspca_dev, 0); + if (gspca_dev->present) + vicam_set_camera_power(gspca_dev, 0); } /* Table of supported USB devices */ diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c index fbb6ed25ec31..ecada178bceb 100644 --- a/drivers/media/video/gspca/xirlink_cit.c +++ b/drivers/media/video/gspca/xirlink_cit.c @@ -995,14 +995,12 @@ static int sd_config(struct gspca_dev *gspca_dev, case CIT_MODEL0: cam->cam_mode = model0_mode; cam->nmodes = ARRAY_SIZE(model0_mode); - cam->reverse_alts = 1; gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP)); sd->sof_len = 4; break; case CIT_MODEL1: cam->cam_mode = cif_yuv_mode; cam->nmodes = ARRAY_SIZE(cif_yuv_mode); - cam->reverse_alts = 1; gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP); sd->sof_len = 4; break; @@ -2791,7 +2789,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) } /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); return 0; @@ -2814,7 +2812,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) break; } - alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1]; + alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); if (packet_size <= min_packet_size) return -EIO; diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 0202fead6b97..b9e15bb0328b 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -5381,12 +5381,12 @@ static const struct usb_action tas5130c_NoFlikerScale[] = { {} }; -static const struct usb_action gc0303_InitialScale[] = { +/* from usbvm305.inf 0ac8:305b 07/06/15 (3 - tas5130c) */ +static const struct usb_action gc0303_Initial[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc, - * 0<->10 */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ @@ -5405,29 +5405,22 @@ static const struct usb_action gc0303_InitialScale[] = { * 6<->8 */ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ - {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ - {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ -/*?? {0xaa, 0x01, 0x0000}, */ {0xaa, 0x01, 0x0000}, {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xaa, 0x1b, 0x0000}, {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ - {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ - {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ - {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ - {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ -/*?? {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, */ + {0xaa, 0x0a, 0x0002}, + {0xaa, 0x0b, 0x0000}, + {0xaa, 0x0c, 0x0002}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0002}, + {0xaa, 0x0f, 0x0000}, + {0xaa, 0x10, 0x0002}, + {0xaa, 0x11, 0x0000}, {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ @@ -5442,17 +5435,18 @@ static const struct usb_action gc0303_InitialScale[] = { {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN}, {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {0xaa, 0x1b, 0x0000}, {} }; -static const struct usb_action gc0303_Initial[] = { +static const struct usb_action gc0303_InitialScale[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */ {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */ {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */ - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */ @@ -5471,34 +5465,26 @@ static const struct usb_action gc0303_Initial[] = { * 8<->6 */ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */ {0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */ - {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */ - {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */ - {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ - {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ - {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ -/*?? {0xaa, 0x01, 0x0000}, */ {0xaa, 0x01, 0x0000}, {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ + {0xaa, 0x1b, 0x0000}, {0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */ {0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */ {0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */ {0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */ - {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */ - {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */ - {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */ - {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */ - {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */ - {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ - {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ - {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ -/*?? {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, */ + {0xaa, 0x0a, 0x0001}, + {0xaa, 0x0b, 0x0000}, + {0xaa, 0x0c, 0x0001}, + {0xaa, 0x0d, 0x0000}, + {0xaa, 0x0e, 0x0001}, + {0xaa, 0x0f, 0x0000}, + {0xaa, 0x10, 0x0001}, + {0xaa, 0x11, 0x0000}, {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ {0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */ - {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */ {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */ @@ -5508,36 +5494,37 @@ static const struct usb_action gc0303_Initial[] = { {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */ {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */ {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */ - {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */ + {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN}, {0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */ {0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */ + {0xaa, 0x1b, 0x0000}, {} }; -static const struct usb_action gc0303_50HZScale[] = { +static const struct usb_action gc0303_50HZ[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ - {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */ + {0xaa, 0x84, 0x0063}, {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */ {0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ - {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ + {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP}, {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {0xa0, 0x7f, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_50HZ[] = { +static const struct usb_action gc0303_50HZScale[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0003}, /* 00,83,03,aa */ {0xaa, 0x84, 0x0054}, /* 00,84,54,aa */ @@ -5550,21 +5537,21 @@ static const struct usb_action gc0303_50HZ[] = { {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */ {0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */ - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ + {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */ {0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */ {0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */ {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */ {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {0xa0, 0x7f, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_60HZScale[] = { +static const struct usb_action gc0303_60HZ[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */ - {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */ + {0xaa, 0x83, 0x0000}, + {0xaa, 0x84, 0x003b}, {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ @@ -5581,14 +5568,14 @@ static const struct usb_action gc0303_60HZScale[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_60HZ[] = { +static const struct usb_action gc0303_60HZScale[] = { {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ - {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */ - {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */ + {0xaa, 0x83, 0x0000}, + {0xaa, 0x84, 0x0076}, {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */ {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */ @@ -5605,18 +5592,18 @@ static const struct usb_action gc0303_60HZ[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */ {0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */ - {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */ + {0xa0, 0x80, ZC3XX_R18D_YTARGET}, {} }; -static const struct usb_action gc0303_NoFlikerScale[] = { +static const struct usb_action gc0303_NoFliker[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */ - {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */ - {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */ + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ @@ -5631,14 +5618,14 @@ static const struct usb_action gc0303_NoFlikerScale[] = { {} }; -static const struct usb_action gc0303_NoFliker[] = { +static const struct usb_action gc0303_NoFlikerScale[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ {0xaa, 0x84, 0x0020}, /* 00,84,20,aa */ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */ - {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */ - {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */ + {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID}, + {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW}, {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */ {0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */ @@ -5809,7 +5796,7 @@ static void setmatrix(struct gspca_dev *gspca_dev) static const u8 tas5130c_matrix[9] = {0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68}; static const u8 gc0303_matrix[9] = - {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b}; + {0x6c, 0xea, 0xea, 0xea, 0x6c, 0xea, 0xea, 0xea, 0x6c}; static const u8 *matrix_tb[SENSOR_MAX] = { [SENSOR_ADCM2700] = adcm2700_matrix, [SENSOR_CS2102] = ov7620_matrix, @@ -6426,10 +6413,6 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.ctrls = sd->ctrls; sd->quality = QUALITY_DEF; - /* if USB 1.1, let some bandwidth for the audio device */ - if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) - gspca_dev->nbalt--; - return 0; } diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index 3f1a5b1beeba..e5eb56a5b618 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -49,7 +49,7 @@ module_param(default_audio_input, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / " "1=RCA front / 2=S/PDIF"); -static int boost_audio; +static bool boost_audio; module_param(boost_audio, bool, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(boost_audio, "boost the audio signal"); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 3ab875d036e1..a7c41d32f414 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -244,7 +244,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, /* ----------------------------------------------------------------------- */ -static void ir_key_poll(struct IR_i2c *ir) +static int ir_key_poll(struct IR_i2c *ir) { static u32 ir_key, ir_raw; int rc; @@ -253,20 +253,28 @@ static void ir_key_poll(struct IR_i2c *ir) rc = ir->get_key(ir, &ir_key, &ir_raw); if (rc < 0) { dprintk(2,"error\n"); - return; + return rc; } if (rc) { dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key); rc_keydown(ir->rc, ir_key, 0); } + return 0; } static void ir_work(struct work_struct *work) { + int rc; struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); - ir_key_poll(ir); + rc = ir_key_poll(ir); + if (rc == -ENODEV) { + rc_unregister_device(ir->rc); + ir->rc = NULL; + return; + } + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); } @@ -446,7 +454,8 @@ static int ir_remove(struct i2c_client *client) cancel_delayed_work_sync(&ir->work); /* unregister device */ - rc_unregister_device(ir->rc); + if (ir->rc) + rc_unregister_device(ir->rc); /* free memory */ kfree(ir); @@ -489,11 +498,3 @@ static void __exit ir_fini(void) module_init(ir_init); module_exit(ir_fini); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 41108a9a195e..544af91cbdc1 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -99,7 +99,7 @@ static int i2c_clock_period[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, static unsigned int cardtype_c = 1; static unsigned int tuner_c = 1; -static unsigned int radio_c = 1; +static bool radio_c = 1; static unsigned int i2c_clock_period_c = 1; static char pal[] = "---"; static char secam[] = "--"; diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 9332920ca4ff..7b9ec1cfeb80 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -25,7 +25,7 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv); int ivtv_i2c_register(struct ivtv *itv, unsigned idx); struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw); -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter */ int init_ivtv_i2c(struct ivtv *itv); void exit_ivtv_i2c(struct ivtv *itv); diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 6b7c9c823330..d0fbfcf7133d 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -58,7 +58,7 @@ /* card parameters */ static int ivtvfb_card_id = -1; static int ivtvfb_debug = 0; -static int osd_laced; +static bool osd_laced; static int osd_depth; static int osd_upper; static int osd_left; diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 82c8817bd32d..4b021e1ee5f2 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h @@ -163,7 +163,6 @@ struct m5mols_version { * @ffmt: current fmt according to resolution type * @res_type: current resolution type * @irq_waitq: waitqueue for the capture - * @work_irq: workqueue for the IRQ * @flags: state variable for the interrupt handler * @handle: control handler * @autoexposure: Auto Exposure control @@ -175,14 +174,12 @@ struct m5mols_version { * @ver: information of the version * @cap: the capture mode attributes * @power: current sensor's power status - * @ctrl_sync: true means all controls of the sensor are initialized - * @int_capture: true means the capture interrupt is issued once + * @isp_ready: 1 when the ISP controller has completed booting + * @ctrl_sync: 1 when the control handler state is restored in H/W * @lock_ae: true means the Auto Exposure is locked * @lock_awb: true means the Aut WhiteBalance is locked * @resolution: register value for current resolution - * @interrupt: register value for current interrupt status * @mode: register value for current operation mode - * @mode_save: register value for current operation mode for saving * @set_power: optional power callback to the board code */ struct m5mols_info { @@ -191,16 +188,16 @@ struct m5mols_info { struct media_pad pad; struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; int res_type; + wait_queue_head_t irq_waitq; - struct work_struct work_irq; - unsigned long flags; + atomic_t irq_done; struct v4l2_ctrl_handler handle; + /* Autoexposure/exposure control cluster */ - struct { - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; + struct v4l2_ctrl *autoexposure; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *autowb; struct v4l2_ctrl *colorfx; struct v4l2_ctrl *saturation; @@ -208,21 +205,19 @@ struct m5mols_info { struct m5mols_version ver; struct m5mols_capture cap; - bool power; - bool ctrl_sync; + + unsigned int isp_ready:1; + unsigned int power:1; + unsigned int ctrl_sync:1; + bool lock_ae; bool lock_awb; u8 resolution; - u8 interrupt; u8 mode; - u8 mode_save; + int (*set_power)(struct device *dev, int on); }; -#define ST_CAPT_IRQ 0 - -#define is_powered(__info) (__info->power) -#define is_ctrl_synced(__info) (__info->ctrl_sync) #define is_available_af(__info) (__info->ver.af) #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) #define is_manufacturer(__info, __manufacturer) \ @@ -257,7 +252,15 @@ int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg_comb, u8 *val); int m5mols_read_u16(struct v4l2_subdev *sd, u32 reg_comb, u16 *val); int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); + +int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, + int timeout); + +/* Mask value for busy waiting until M-5MOLS I2C interface is initialized */ +#define M5MOLS_I2C_RDY_WAIT_FL (1 << 16) +/* ISP state transition timeout, in ms */ +#define M5MOLS_MODE_CHANGE_TIMEOUT 200 +#define M5MOLS_BUSY_WAIT_DEF_TIMEOUT 250 /* * Mode operation of the M-5MOLS @@ -282,7 +285,8 @@ int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 value); int m5mols_mode(struct m5mols_info *info, u8 mode); int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg); -int m5mols_sync_controls(struct m5mols_info *info); +int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout); +int m5mols_restore_controls(struct m5mols_info *info); int m5mols_start_capture(struct m5mols_info *info); int m5mols_do_scenemode(struct m5mols_info *info, u8 mode); int m5mols_lock_3a(struct m5mols_info *info, bool lock); diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c index 3248ac805711..ba25e8e2ba4c 100644 --- a/drivers/media/video/m5mols/m5mols_capture.c +++ b/drivers/media/video/m5mols/m5mols_capture.c @@ -1,3 +1,4 @@ + /* * The Capture code for Fujitsu M-5MOLS ISP * @@ -25,26 +26,11 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/m5mols.h> +#include <media/s5p_fimc.h> #include "m5mols.h" #include "m5mols_reg.h" -static int m5mols_capture_error_handler(struct m5mols_info *info, - int timeout) -{ - int ret; - - /* Disable all interrupts and clear relevant interrupt staus bits */ - ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, - info->interrupt & ~(REG_INT_CAPTURE)); - if (ret) - return ret; - - if (timeout == 0) - return -ETIMEDOUT; - - return 0; -} /** * m5mols_read_rational - I2C read of a rational number * @@ -121,69 +107,54 @@ int m5mols_start_capture(struct m5mols_info *info) { struct v4l2_subdev *sd = &info->sd; u8 resolution = info->resolution; - int timeout; int ret; /* - * Preparing capture. Setting control & interrupt before entering - * capture mode - * - * 1) change to MONITOR mode for operating control & interrupt - * 2) set controls (considering v4l2_control value & lock 3A) - * 3) set interrupt - * 4) change to CAPTURE mode + * Synchronize the controls, set the capture frame resolution and color + * format. The frame capture is initiated during switching from Monitor + * to Capture mode. */ ret = m5mols_mode(info, REG_MONITOR); if (!ret) - ret = m5mols_sync_controls(info); + ret = m5mols_restore_controls(info); if (!ret) - ret = m5mols_lock_3a(info, true); + ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); + if (!ret) + ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); if (!ret) - ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); + ret = m5mols_lock_3a(info, true); if (!ret) ret = m5mols_mode(info, REG_CAPTURE); - if (!ret) { - /* Wait for capture interrupt, after changing capture mode */ - timeout = wait_event_interruptible_timeout(info->irq_waitq, - test_bit(ST_CAPT_IRQ, &info->flags), - msecs_to_jiffies(2000)); - if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) - ret = m5mols_capture_error_handler(info, timeout); - } + if (!ret) + /* Wait until a frame is captured to ISP internal memory */ + ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); if (!ret) ret = m5mols_lock_3a(info, false); if (ret) return ret; + /* - * Starting capture. Setting capture frame count and resolution and - * the format(available format: JPEG, Bayer RAW, YUV). - * - * 1) select single or multi(enable to 25), format, size - * 2) set interrupt - * 3) start capture(for main image, now) - * 4) get information - * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device) + * Initiate the captured data transfer to a MIPI-CSI receiver. */ ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); if (!ret) - ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); - if (!ret) - ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); - if (!ret) - ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); - if (!ret) ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); if (!ret) { + bool captured = false; + unsigned int size; + /* Wait for the capture completion interrupt */ - timeout = wait_event_interruptible_timeout(info->irq_waitq, - test_bit(ST_CAPT_IRQ, &info->flags), - msecs_to_jiffies(2000)); - if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { + ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); + if (!ret) { + captured = true; ret = m5mols_capture_info(info); - if (!ret) - v4l2_subdev_notify(sd, 0, &info->cap.total); } + size = captured ? info->cap.main : 0; + v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n", + __func__, size, info->cap.thumb); + + v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size); } - return m5mols_capture_error_handler(info, timeout); + return ret; } diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index e0f09e531800..93d768db9f33 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -135,10 +135,13 @@ static u32 m5mols_swap_byte(u8 *data, u8 length) * @reg: combination of size, category and command for the I2C packet * @size: desired size of I2C packet * @val: read value + * + * Returns 0 on success, or else negative errno. */ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct m5mols_info *info = to_m5mols(sd); u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; u8 category = I2C_CATEGORY(reg); u8 cmd = I2C_COMMAND(reg); @@ -168,15 +171,17 @@ static int m5mols_read(struct v4l2_subdev *sd, u32 size, u32 reg, u32 *val) usleep_range(200, 200); ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", - size, category, cmd, ret); - return ret; + + if (ret == 2) { + *val = m5mols_swap_byte(&rbuf[1], size); + return 0; } - *val = m5mols_swap_byte(&rbuf[1], size); + if (info->isp_ready) + v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", + size, category, cmd, ret); - return 0; + return ret < 0 ? ret : -EIO; } int m5mols_read_u8(struct v4l2_subdev *sd, u32 reg, u8 *val) @@ -229,10 +234,13 @@ int m5mols_read_u32(struct v4l2_subdev *sd, u32 reg, u32 *val) * m5mols_write - I2C command write function * @reg: combination of size, category and command for the I2C packet * @val: value to write + * + * Returns 0 on success, or else negative errno. */ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct m5mols_info *info = to_m5mols(sd); u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; u8 category = I2C_CATEGORY(reg); u8 cmd = I2C_COMMAND(reg); @@ -263,28 +271,45 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) usleep_range(200, 200); ret = i2c_transfer(client->adapter, msg, 1); - if (ret < 0) { - v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", - size, category, cmd, ret); - return ret; - } + if (ret == 1) + return 0; - return 0; + if (info->isp_ready) + v4l2_err(sd, "write failed: cat:%02x cmd:%02x ret:%d\n", + category, cmd, ret); + + return ret < 0 ? ret : -EIO; } -int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u8 mask) +/** + * m5mols_busy_wait - Busy waiting with I2C register polling + * @reg: the I2C_REG() address of an 8-bit status register to check + * @value: expected status register value + * @mask: bit mask for the read status register value + * @timeout: timeout in miliseconds, or -1 for default timeout + * + * The @reg register value is ORed with @mask before comparing with @value. + * + * Return: 0 if the requested condition became true within less than + * @timeout ms, or else negative errno. + */ +int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask, + int timeout) { - u8 busy; - int i; - int ret; + int ms = timeout < 0 ? M5MOLS_BUSY_WAIT_DEF_TIMEOUT : timeout; + unsigned long end = jiffies + msecs_to_jiffies(ms); + u8 status; - for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { - ret = m5mols_read_u8(sd, I2C_REG(category, cmd, 1), &busy); - if (ret < 0) + do { + int ret = m5mols_read_u8(sd, reg, &status); + + if (ret < 0 && !(mask & M5MOLS_I2C_RDY_WAIT_FL)) return ret; - if ((busy & mask) == mask) + if (!ret && (status & mask & 0xff) == (value & 0xff)) return 0; - } + usleep_range(100, 250); + } while (ms > 0 && time_is_after_jiffies(end)); + return -EBUSY; } @@ -307,6 +332,20 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) return ret; } +int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 irq_mask, u32 timeout) +{ + struct m5mols_info *info = to_m5mols(sd); + + int ret = wait_event_interruptible_timeout(info->irq_waitq, + atomic_add_unless(&info->irq_done, -1, 0), + msecs_to_jiffies(timeout)); + if (ret <= 0) + return ret ? ret : -ETIMEDOUT; + + return m5mols_busy_wait(sd, SYSTEM_INT_FACTOR, irq_mask, + M5MOLS_I2C_RDY_WAIT_FL | irq_mask, -1); +} + /** * m5mols_reg_mode - Write the mode and check busy status * @@ -316,8 +355,10 @@ int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg) static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode) { int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); - - return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); + if (ret < 0) + return ret; + return m5mols_busy_wait(sd, SYSTEM_SYSMODE, mode, 0xff, + M5MOLS_MODE_CHANGE_TIMEOUT); } /** @@ -338,13 +379,13 @@ int m5mols_mode(struct m5mols_info *info, u8 mode) return ret; ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); - if ((!ret && reg == mode) || ret) + if (ret || reg == mode) return ret; switch (reg) { case REG_PARAMETER: ret = m5mols_reg_mode(sd, REG_MONITOR); - if (!ret && mode == REG_MONITOR) + if (mode == REG_MONITOR) break; if (!ret) ret = m5mols_reg_mode(sd, REG_CAPTURE); @@ -361,7 +402,7 @@ int m5mols_mode(struct m5mols_info *info, u8 mode) case REG_CAPTURE: ret = m5mols_reg_mode(sd, REG_MONITOR); - if (!ret && mode == REG_MONITOR) + if (mode == REG_MONITOR) break; if (!ret) ret = m5mols_reg_mode(sd, REG_PARAMETER); @@ -570,26 +611,25 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = { }; /** - * m5mols_sync_controls - Apply default scene mode and the current controls + * m5mols_restore_controls - Apply current control values to the registers * - * This is used only streaming for syncing between v4l2_ctrl framework and - * m5mols's controls. First, do the scenemode to the sensor, then call - * v4l2_ctrl_handler_setup. It can be same between some commands and - * the scenemode's in the default v4l2_ctrls. But, such commands of control - * should be prior to the scenemode's one. + * m5mols_do_scenemode() handles all parameters for which there is yet no + * individual control. It should be replaced at some point by setting each + * control individually, in required register set up order. */ -int m5mols_sync_controls(struct m5mols_info *info) +int m5mols_restore_controls(struct m5mols_info *info) { - int ret = -EINVAL; + int ret; - if (!is_ctrl_synced(info)) { - ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); - if (ret) - return ret; + if (info->ctrl_sync) + return 0; - v4l2_ctrl_handler_setup(&info->handle); - info->ctrl_sync = true; - } + ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); + if (ret) + return ret; + + ret = v4l2_ctrl_handler_setup(&info->handle); + info->ctrl_sync = !ret; return ret; } @@ -613,7 +653,7 @@ static int m5mols_start_monitor(struct m5mols_info *info) if (!ret) ret = m5mols_mode(info, REG_MONITOR); if (!ret) - ret = m5mols_sync_controls(info); + ret = m5mols_restore_controls(info); return ret; } @@ -645,17 +685,25 @@ static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); struct m5mols_info *info = to_m5mols(sd); + int ispstate = info->mode; int ret; - info->mode_save = info->mode; + /* + * If needed, defer restoring the controls until + * the device is fully initialized. + */ + if (!info->isp_ready) { + info->ctrl_sync = 0; + return 0; + } ret = m5mols_mode(info, REG_PARAMETER); - if (!ret) - ret = m5mols_set_ctrl(ctrl); - if (!ret) - ret = m5mols_mode(info, info->mode_save); - - return ret; + if (ret < 0) + return ret; + ret = m5mols_set_ctrl(ctrl); + if (ret < 0) + return ret; + return m5mols_mode(info, ispstate); } static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { @@ -669,10 +717,10 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) const struct m5mols_platform_data *pdata = info->pdata; int ret; - if (enable) { - if (is_powered(info)) - return 0; + if (info->power == enable) + return 0; + if (enable) { if (info->set_power) { ret = info->set_power(&client->dev, 1); if (ret) @@ -686,15 +734,11 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) } gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); - usleep_range(1000, 1000); - info->power = true; + info->power = 1; return ret; } - if (!is_powered(info)) - return 0; - ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); if (ret) return ret; @@ -703,8 +747,9 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable) info->set_power(&client->dev, 0); gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); - usleep_range(1000, 1000); - info->power = false; + + info->isp_ready = 0; + info->power = 0; return ret; } @@ -717,21 +762,29 @@ int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, } /** - * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. + * m5mols_fw_start - M-5MOLS internal ARM controller initialization * - * Booting internal ARM core makes the M-5MOLS is ready for getting commands - * with I2C. It's the first thing to be done after it powered up. It must wait - * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. + * Execute the M-5MOLS internal ARM controller initialization sequence. + * This function should be called after the supply voltage has been + * applied and before any requests to the device are made. */ -static int m5mols_sensor_armboot(struct v4l2_subdev *sd) +static int m5mols_fw_start(struct v4l2_subdev *sd) { + struct m5mols_info *info = to_m5mols(sd); int ret; - ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); + atomic_set(&info->irq_done, 0); + /* Wait until I2C slave is initialized in Flash Writer mode */ + ret = m5mols_busy_wait(sd, FLASH_CAM_START, REG_IN_FLASH_MODE, + M5MOLS_I2C_RDY_WAIT_FL | 0xff, -1); + if (!ret) + ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); + if (!ret) + ret = m5mols_wait_interrupt(sd, REG_INT_MODE, 2000); if (ret < 0) return ret; - msleep(520); + info->isp_ready = 1; ret = m5mols_get_version(sd); if (!ret) @@ -743,7 +796,8 @@ static int m5mols_sensor_armboot(struct v4l2_subdev *sd) ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); if (!ret) - ret = m5mols_enable_interrupt(sd, REG_INT_AF); + ret = m5mols_enable_interrupt(sd, + REG_INT_AF | REG_INT_CAPTURE); return ret; } @@ -780,7 +834,7 @@ static int m5mols_init_controls(struct m5mols_info *info) 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, - 1, 0, V4L2_EXPOSURE_MANUAL); + 1, 0, V4L2_EXPOSURE_AUTO); sd->ctrl_handler = &info->handle; if (info->handle.error) { @@ -809,16 +863,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) if (on) { ret = m5mols_sensor_power(info, true); if (!ret) - ret = m5mols_sensor_armboot(sd); - if (!ret) - ret = m5mols_init_controls(info); - if (ret) - return ret; - - info->ffmt[M5MOLS_RESTYPE_MONITOR] = - m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; - info->ffmt[M5MOLS_RESTYPE_CAPTURE] = - m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; + ret = m5mols_fw_start(sd); return ret; } @@ -829,17 +874,14 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on) if (!ret) ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); if (!ret) - ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, - REG_AF_IDLE); - if (!ret) - v4l2_info(sd, "Success soft-landing lens\n"); + ret = m5mols_busy_wait(sd, SYSTEM_STATUS, REG_AF_IDLE, + 0xff, -1); + if (ret < 0) + v4l2_warn(sd, "Soft landing lens failed\n"); } ret = m5mols_sensor_power(info, false); - if (!ret) { - v4l2_ctrl_handler_free(&info->handle); - info->ctrl_sync = false; - } + info->ctrl_sync = 0; return ret; } @@ -865,52 +907,33 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = { .log_status = m5mols_log_status, }; +/* + * V4L2 subdev internal operations + */ +static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + *format = m5mols_default_ffmt[0]; + return 0; +} + +static const struct v4l2_subdev_internal_ops m5mols_subdev_internal_ops = { + .open = m5mols_open, +}; + static const struct v4l2_subdev_ops m5mols_ops = { .core = &m5mols_core_ops, .pad = &m5mols_pad_ops, .video = &m5mols_video_ops, }; -static void m5mols_irq_work(struct work_struct *work) -{ - struct m5mols_info *info = - container_of(work, struct m5mols_info, work_irq); - struct v4l2_subdev *sd = &info->sd; - u8 reg; - int ret; - - if (!is_powered(info) || - m5mols_read_u8(sd, SYSTEM_INT_FACTOR, &info->interrupt)) - return; - - switch (info->interrupt & REG_INT_MASK) { - case REG_INT_AF: - if (!is_available_af(info)) - break; - ret = m5mols_read_u8(sd, AF_STATUS, ®); - v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", - reg == REG_AF_FAIL ? "Failed" : - reg == REG_AF_SUCCESS ? "Success" : - reg == REG_AF_IDLE ? "Idle" : "Busy"); - break; - case REG_INT_CAPTURE: - if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) - wake_up_interruptible(&info->irq_waitq); - - v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); - break; - default: - v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); - break; - }; -} - static irqreturn_t m5mols_irq_handler(int irq, void *data) { - struct v4l2_subdev *sd = data; - struct m5mols_info *info = to_m5mols(sd); + struct m5mols_info *info = to_m5mols(data); - schedule_work(&info->work_irq); + atomic_set(&info->irq_done, 1); + wake_up_interruptible(&info->irq_waitq); return IRQ_HANDLED; } @@ -961,7 +984,9 @@ static int __devinit m5mols_probe(struct i2c_client *client, sd = &info->sd; strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); v4l2_i2c_subdev_init(sd, client, &m5mols_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &m5mols_subdev_internal_ops; info->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, 1, &info->pad, 0); if (ret < 0) @@ -969,7 +994,6 @@ static int __devinit m5mols_probe(struct i2c_client *client, sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; init_waitqueue_head(&info->irq_waitq); - INIT_WORK(&info->work_irq, m5mols_irq_work); ret = request_irq(client->irq, m5mols_irq_handler, IRQF_TRIGGER_RISING, MODULE_NAME, sd); if (ret) { @@ -977,7 +1001,20 @@ static int __devinit m5mols_probe(struct i2c_client *client, goto out_me; } info->res_type = M5MOLS_RESTYPE_MONITOR; - return 0; + info->ffmt[0] = m5mols_default_ffmt[0]; + info->ffmt[1] = m5mols_default_ffmt[1]; + + ret = m5mols_sensor_power(info, true); + if (ret) + goto out_me; + + ret = m5mols_fw_start(sd); + if (!ret) + ret = m5mols_init_controls(info); + + m5mols_sensor_power(info, false); + if (!ret) + return 0; out_me: media_entity_cleanup(&sd->entity); out_reg: @@ -995,6 +1032,7 @@ static int __devexit m5mols_remove(struct i2c_client *client) struct m5mols_info *info = to_m5mols(sd); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); free_irq(client->irq, sd); regulator_bulk_free(ARRAY_SIZE(supplies), supplies); diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h index c755bd6edfe9..ae4aced0f9b2 100644 --- a/drivers/media/video/m5mols/m5mols_reg.h +++ b/drivers/media/video/m5mols/m5mols_reg.h @@ -55,39 +55,31 @@ * There is many registers between customer version address and awb one. For * more specific contents, see definition if file m5mols.h. */ -#define CAT0_VER_CUSTOMER 0x00 /* customer version */ -#define CAT0_VER_PROJECT 0x01 /* project version */ -#define CAT0_VER_FIRMWARE 0x02 /* Firmware version */ -#define CAT0_VER_HARDWARE 0x04 /* Hardware version */ -#define CAT0_VER_PARAMETER 0x06 /* Parameter version */ -#define CAT0_VER_AWB 0x08 /* Auto WB version */ -#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ -#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ -#define CAT0_STATUS 0x0c /* SYSTEM mode status register */ -#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ -#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ - -#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, CAT0_VER_CUSTOMER, 1) -#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, CAT0_VER_PROJECT, 1) -#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, CAT0_VER_FIRMWARE, 2) -#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, CAT0_VER_HARDWARE, 2) -#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, CAT0_VER_PARAMETER, 2) -#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, CAT0_VER_AWB, 2) - -#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) +#define SYSTEM_VER_CUSTOMER I2C_REG(CAT_SYSTEM, 0x00, 1) +#define SYSTEM_VER_PROJECT I2C_REG(CAT_SYSTEM, 0x01, 1) +#define SYSTEM_VER_FIRMWARE I2C_REG(CAT_SYSTEM, 0x02, 2) +#define SYSTEM_VER_HARDWARE I2C_REG(CAT_SYSTEM, 0x04, 2) +#define SYSTEM_VER_PARAMETER I2C_REG(CAT_SYSTEM, 0x06, 2) +#define SYSTEM_VER_AWB I2C_REG(CAT_SYSTEM, 0x08, 2) + +#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, 0x0b, 1) #define REG_SYSINIT 0x00 /* SYSTEM mode */ #define REG_PARAMETER 0x01 /* PARAMETER mode */ #define REG_MONITOR 0x02 /* MONITOR mode */ #define REG_CAPTURE 0x03 /* CAPTURE mode */ #define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) -#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) +#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, 0x0a, 1) #define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ #define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ #define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ +/* SYSTEM mode status */ +#define SYSTEM_STATUS I2C_REG(CAT_SYSTEM, 0x0c, 1) -#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) -#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) +/* Interrupt pending register */ +#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, 0x10, 1) +/* interrupt enable register */ +#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, 0x11, 1) #define REG_INT_MODE (1 << 0) #define REG_INT_AF (1 << 1) #define REG_INT_ZOOM (1 << 2) @@ -105,20 +97,20 @@ * can handle with preview(MONITOR) resolution size/frame per second/interface * between the sensor and the Application Processor/even the image effect. */ -#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ -#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ -#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ -#define CAT1_EFFECT 0x0b /* image effects */ -#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) +/* Resolution in the MONITOR mode */ +#define PARM_MON_SIZE I2C_REG(CAT_PARAM, 0x01, 1) -#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) +/* Frame rate */ +#define PARM_MON_FPS I2C_REG(CAT_PARAM, 0x02, 1) #define REG_FPS_30 0x02 -#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) +/* Video bus between the sensor and a host processor */ +#define PARM_INTERFACE I2C_REG(CAT_PARAM, 0x00, 1) #define REG_INTERFACE_MIPI 0x02 -#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) +/* Image effects */ +#define PARM_EFFECT I2C_REG(CAT_PARAM, 0x0b, 1) #define REG_EFFECT_OFF 0x00 #define REG_EFFECT_NEGA 0x01 #define REG_EFFECT_EMBOSS 0x06 @@ -135,39 +127,37 @@ * another options like zoom/color effect(different with effect in PARAMETER * mode)/anti hand shaking algorithm. */ -#define CAT2_ZOOM 0x01 /* set the zoom position & execute */ -#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ -#define CAT2_CFIXB 0x09 /* CB value for color effect */ -#define CAT2_CFIXR 0x0a /* CR value for color effect */ -#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ -#define CAT2_CHROMA_LVL 0x0f /* set chroma level */ -#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ -#define CAT2_EDGE_LVL 0x11 /* set sharpness level */ -#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ -#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ - -#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) - -#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) -#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) + +/* Target digital zoom position */ +#define MON_ZOOM I2C_REG(CAT_MONITOR, 0x01, 1) + +/* CR value for color effect */ +#define MON_CFIXR I2C_REG(CAT_MONITOR, 0x0a, 1) +/* CB value for color effect */ +#define MON_CFIXB I2C_REG(CAT_MONITOR, 0x09, 1) #define REG_CFIXB_SEPIA 0xd8 #define REG_CFIXR_SEPIA 0x18 -#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) +#define MON_EFFECT I2C_REG(CAT_MONITOR, 0x0b, 1) #define REG_COLOR_EFFECT_OFF 0x00 #define REG_COLOR_EFFECT_ON 0x01 -#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) -#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) +/* Chroma enable */ +#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, 0x10, 1) +/* Chroma level */ +#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, 0x0f, 1) #define REG_CHROMA_OFF 0x00 #define REG_CHROMA_ON 0x01 -#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) -#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) +/* Sharpness on/off */ +#define MON_EDGE_EN I2C_REG(CAT_MONITOR, 0x12, 1) +/* Sharpness level */ +#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, 0x11, 1) #define REG_EDGE_OFF 0x00 #define REG_EDGE_ON 0x01 -#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) +/* Set color tone (contrast) */ +#define MON_TONE_CTL I2C_REG(CAT_MONITOR, 0x25, 1) /* * Category 3 - Auto Exposure @@ -179,27 +169,20 @@ * different. So, this category also provide getting the max/min values. And, * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. */ -#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ -#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ -#define CAT3_ISO 0x05 /* set ISO */ -#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ -#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ -#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ -#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ -#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ -#define CAT3_AE_INDEX 0x38 /* AE index */ - -#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) + +/* Auto Exposure locking */ +#define AE_LOCK I2C_REG(CAT_AE, 0x00, 1) #define REG_AE_UNLOCK 0x00 #define REG_AE_LOCK 0x01 -#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) +/* Auto Exposure algorithm mode */ +#define AE_MODE I2C_REG(CAT_AE, 0x01, 1) #define REG_AE_OFF 0x00 /* AE off */ #define REG_AE_ALL 0x01 /* calc AE in all block integral */ #define REG_AE_CENTER 0x03 /* calc AE in center weighted */ #define REG_AE_SPOT 0x06 /* calc AE in specific spot */ -#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) +#define AE_ISO I2C_REG(CAT_AE, 0x05, 1) #define REG_ISO_AUTO 0x00 #define REG_ISO_50 0x01 #define REG_ISO_100 0x02 @@ -207,8 +190,10 @@ #define REG_ISO_400 0x04 #define REG_ISO_800 0x05 -#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) -#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) +/* EV (scenemode) preset for MONITOR */ +#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, 0x0a, 1) +/* EV (scenemode) preset for CAPTURE */ +#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, 0x0b, 1) #define REG_SCENE_NORMAL 0x00 #define REG_SCENE_PORTRAIT 0x01 #define REG_SCENE_LANDSCAPE 0x02 @@ -224,11 +209,14 @@ #define REG_SCENE_TEXT 0x0c #define REG_SCENE_CANDLE 0x0d -#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) -#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) -#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) +/* Manual gain in MONITOR mode */ +#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, 0x12, 2) +/* Maximum gain in MONITOR mode */ +#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, 0x1a, 2) +/* Manual gain in CAPTURE mode */ +#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, 0x26, 2) -#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) +#define AE_INDEX I2C_REG(CAT_AE, 0x38, 1) #define REG_AE_INDEX_20_NEG 0x00 #define REG_AE_INDEX_15_NEG 0x01 #define REG_AE_INDEX_10_NEG 0x02 @@ -241,22 +229,19 @@ /* * Category 6 - White Balance - * - * This category provide AWB locking/mode/preset/speed/gain bias, etc. */ -#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ -#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ -#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ -#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) +/* Auto Whitebalance locking */ +#define AWB_LOCK I2C_REG(CAT_WB, 0x00, 1) #define REG_AWB_UNLOCK 0x00 #define REG_AWB_LOCK 0x01 -#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) +#define AWB_MODE I2C_REG(CAT_WB, 0x02, 1) #define REG_AWB_AUTO 0x01 /* AWB off */ #define REG_AWB_PRESET 0x02 /* AWB preset */ -#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) +/* Manual WB (preset) */ +#define AWB_MANUAL I2C_REG(CAT_WB, 0x03, 1) #define REG_AWB_INCANDESCENT 0x01 #define REG_AWB_FLUORESCENT_1 0x02 #define REG_AWB_FLUORESCENT_2 0x03 @@ -269,42 +254,25 @@ /* * Category 7 - EXIF information */ -#define CAT7_INFO_EXPTIME_NU 0x00 -#define CAT7_INFO_EXPTIME_DE 0x04 -#define CAT7_INFO_TV_NU 0x08 -#define CAT7_INFO_TV_DE 0x0c -#define CAT7_INFO_AV_NU 0x10 -#define CAT7_INFO_AV_DE 0x14 -#define CAT7_INFO_BV_NU 0x18 -#define CAT7_INFO_BV_DE 0x1c -#define CAT7_INFO_EBV_NU 0x20 -#define CAT7_INFO_EBV_DE 0x24 -#define CAT7_INFO_ISO 0x28 -#define CAT7_INFO_FLASH 0x2a -#define CAT7_INFO_SDR 0x2c -#define CAT7_INFO_QVAL 0x2e - -#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) -#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) -#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) -#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) -#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) -#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) -#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) -#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) -#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) -#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) -#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) -#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) -#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) -#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) +#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, 0x00, 4) +#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, 0x04, 4) +#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, 0x08, 4) +#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, 0x0c, 4) +#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, 0x10, 4) +#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, 0x14, 4) +#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, 0x18, 4) +#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, 0x1c, 4) +#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, 0x20, 4) +#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, 0x24, 4) +#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, 0x28, 2) +#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, 0x2a, 2) +#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, 0x2c, 2) +#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, 0x2e, 2) /* * Category 9 - Face Detection */ -#define CAT9_FD_CTL 0x00 - -#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) +#define FD_CTL I2C_REG(CAT_FD, 0x00, 1) #define BIT_FD_EN 0 #define BIT_FD_DRAW_FACE_FRAME 4 #define BIT_FD_DRAW_SMILE_LVL 6 @@ -314,62 +282,50 @@ /* * Category A - Lens Parameter */ -#define CATA_AF_MODE 0x01 -#define CATA_AF_EXECUTE 0x02 -#define CATA_AF_STATUS 0x03 -#define CATA_AF_VERSION 0x0a - -#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) +#define AF_MODE I2C_REG(CAT_LENS, 0x01, 1) #define REG_AF_NORMAL 0x00 /* Normal AF, one time */ #define REG_AF_MACRO 0x01 /* Macro AF, one time */ #define REG_AF_POWEROFF 0x07 -#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) +#define AF_EXECUTE I2C_REG(CAT_LENS, 0x02, 1) #define REG_AF_STOP 0x00 #define REG_AF_EXE_AUTO 0x01 #define REG_AF_EXE_CAF 0x02 -#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) +#define AF_STATUS I2C_REG(CAT_LENS, 0x03, 1) #define REG_AF_FAIL 0x00 #define REG_AF_SUCCESS 0x02 #define REG_AF_IDLE 0x04 #define REG_AF_BUSY 0x05 -#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) +#define AF_VERSION I2C_REG(CAT_LENS, 0x0a, 1) /* * Category B - CAPTURE Parameter */ -#define CATB_YUVOUT_MAIN 0x00 -#define CATB_MAIN_IMAGE_SIZE 0x01 -#define CATB_MCC_MODE 0x1d -#define CATB_WDR_EN 0x2c -#define CATB_LIGHT_CTRL 0x40 -#define CATB_FLASH_CTRL 0x41 - -#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) +#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, 0x00, 1) #define REG_YUV422 0x00 #define REG_BAYER10 0x05 #define REG_BAYER8 0x06 #define REG_JPEG 0x10 -#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) +#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) -#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) +#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) #define REG_MCC_OFF 0x00 #define REG_MCC_NORMAL 0x01 -#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) +#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, 0x2c, 1) #define REG_WDR_OFF 0x00 #define REG_WDR_ON 0x01 #define REG_WDR_AUTO 0x02 -#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) +#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, 0x40, 1) #define REG_LIGHT_OFF 0x00 #define REG_LIGHT_ON 0x01 #define REG_LIGHT_AUTO 0x02 -#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) +#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, 0x41, 1) #define REG_FLASH_OFF 0x00 #define REG_FLASH_ON 0x01 #define REG_FLASH_AUTO 0x02 @@ -377,34 +333,29 @@ /* * Category C - CAPTURE Control */ -#define CATC_CAP_MODE 0x00 -#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ -#define CATC_CAP_START 0x09 -#define CATC_CAP_IMAGE_SIZE 0x0d -#define CATC_CAP_THUMB_SIZE 0x11 - -#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) +#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, 0x00, 1) #define REG_CAP_NONE 0x00 #define REG_CAP_ANTI_SHAKE 0x02 -#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) +/* Select single- or multi-shot capture */ +#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, 0x06, 1) -#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) +#define CAPC_START I2C_REG(CAT_CAPT_CTRL, 0x09, 1) #define REG_CAP_START_MAIN 0x01 #define REG_CAP_START_THUMB 0x03 -#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 4) -#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 4) +#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, 0x0d, 4) +#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, 0x11, 4) /* * Category F - Flash * * This mode provides functions about internal flash stuff and system startup. */ -#define CATF_CAM_START 0x12 /* It starts internal ARM core booting - * after power-up */ -#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) -#define REG_START_ARM_BOOT 0x01 +/* Starts internal ARM core booting after power-up */ +#define FLASH_CAM_START I2C_REG(CAT_FLASH, 0x12, 1) +#define REG_START_ARM_BOOT 0x01 /* write value */ +#define REG_IN_FLASH_MODE 0x00 /* read value */ #endif /* M5MOLS_REG_H */ diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 80ec64d2d6d8..37d20e73908a 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c @@ -51,7 +51,7 @@ static int delivered; * sense. */ -static int alloc_bufs_at_read; +static bool alloc_bufs_at_read; module_param(alloc_bufs_at_read, bool, 0444); MODULE_PARM_DESC(alloc_bufs_at_read, "Non-zero value causes DMA buffers to be allocated when the " @@ -73,11 +73,11 @@ MODULE_PARM_DESC(dma_buf_size, "parameters require larger buffers, an attempt to reallocate " "will be made."); #else /* MCAM_MODE_VMALLOC */ -static const int alloc_bufs_at_read = 0; +static const bool alloc_bufs_at_read = 0; static const int n_dma_bufs = 3; /* Used by S/G_PARM */ #endif /* MCAM_MODE_VMALLOC */ -static int flip; +static bool flip; module_param(flip, bool, 0444); MODULE_PARM_DESC(flip, "If set, the sensor will be instructed to flip the image " @@ -522,6 +522,15 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) */ static void mcam_ctlr_dma_sg(struct mcam_camera *cam) { + /* + * The list-empty condition can hit us at resume time + * if the buffer list was empty when the system was suspended. + */ + if (list_empty(&cam->buffers)) { + set_bit(CF_SG_RESTART, &cam->flags); + return; + } + mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); mcam_sg_next_buffer(cam); mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); @@ -566,6 +575,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) } else { set_bit(CF_SG_RESTART, &cam->flags); singles++; + cam->vb_bufs[0] = NULL; } /* * Now we can give the completed frame back to user space. @@ -661,10 +671,10 @@ static int mcam_ctlr_configure(struct mcam_camera *cam) unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); + clear_bit(CF_SG_RESTART, &cam->flags); cam->dma_setup(cam); mcam_ctlr_image(cam); mcam_set_config_needed(cam, 0); - clear_bit(CF_SG_RESTART, &cam->flags); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; } @@ -873,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) mcam_reset_buffers(cam); mcam_ctlr_irq_enable(cam); cam->state = S_STREAMING; - mcam_ctlr_start(cam); + if (!test_bit(CF_SG_RESTART, &cam->flags)) + mcam_ctlr_start(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; } @@ -1818,11 +1829,15 @@ void mccic_shutdown(struct mcam_camera *cam) void mccic_suspend(struct mcam_camera *cam) { - enum mcam_state cstate = cam->state; + mutex_lock(&cam->s_mutex); + if (cam->users > 0) { + enum mcam_state cstate = cam->state; - mcam_ctlr_stop_dma(cam); - mcam_ctlr_power_down(cam); - cam->state = cstate; + mcam_ctlr_stop_dma(cam); + mcam_ctlr_power_down(cam); + cam->state = cstate; + } + mutex_unlock(&cam->s_mutex); } int mccic_resume(struct mcam_camera *cam) @@ -1839,8 +1854,15 @@ int mccic_resume(struct mcam_camera *cam) mutex_unlock(&cam->s_mutex); set_bit(CF_CONFIG_NEEDED, &cam->flags); - if (cam->state == S_STREAMING) + if (cam->state == S_STREAMING) { + /* + * If there was a buffer in the DMA engine at suspend + * time, put it back on the queue or we'll forget about it. + */ + if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0]) + list_add(&cam->vb_bufs[0]->queue, &cam->buffers); ret = mcam_read_setup(cam); + } return ret; } #endif /* CONFIG_PM */ diff --git a/drivers/media/video/marvell-ccic/mmp-driver.c b/drivers/media/video/marvell-ccic/mmp-driver.c index fb0b124b35f3..0d64e2d7474a 100644 --- a/drivers/media/video/marvell-ccic/mmp-driver.c +++ b/drivers/media/video/marvell-ccic/mmp-driver.c @@ -26,6 +26,7 @@ #include <linux/io.h> #include <linux/delay.h> #include <linux/list.h> +#include <linux/pm.h> #include "mcam-core.h" @@ -310,10 +311,44 @@ static int mmpcam_platform_remove(struct platform_device *pdev) return mmpcam_remove(cam); } +/* + * Suspend/resume support. + */ +#ifdef CONFIG_PM + +static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mmp_camera *cam = mmpcam_find_device(pdev); + + if (state.event != PM_EVENT_SUSPEND) + return 0; + mccic_suspend(&cam->mcam); + return 0; +} + +static int mmpcam_resume(struct platform_device *pdev) +{ + struct mmp_camera *cam = mmpcam_find_device(pdev); + + /* + * Power up unconditionally just in case the core tries to + * touch a register even if nothing was active before; trust + * me, it's better this way. + */ + mmpcam_power_up(&cam->mcam); + return mccic_resume(&cam->mcam); +} + +#endif + static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, .remove = mmpcam_platform_remove, +#ifdef CONFIG_PM + .suspend = mmpcam_suspend, + .resume = mmpcam_resume, +#endif .driver = { .name = "mmp-camera", .owner = THIS_MODULE diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index d0f538857285..d7cd0f633f63 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -69,12 +69,12 @@ MODULE_LICENSE("GPL"); /* module parameters */ static int opmode = OPMODE_AUTO; int msp_debug; /* msp_debug output */ -int msp_once; /* no continuous stereo monitoring */ -int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), +bool msp_once; /* no continuous stereo monitoring */ +bool msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ int msp_standard = 1; /* Override auto detect of audio msp_standard, if needed. */ -int msp_dolby; +bool msp_dolby; int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual (msp34xxg only) 0x00a0-0x03c0 */ diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index 831e8db4368c..fbe5e0715f93 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h @@ -44,10 +44,10 @@ /* module parameters */ extern int msp_debug; -extern int msp_once; -extern int msp_amsound; +extern bool msp_once; +extern bool msp_amsound; extern int msp_standard; -extern int msp_dolby; +extern bool msp_dolby; extern int msp_stereo_thresh; struct msp_state { diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index e2b1029b16cd..097c9d3d04a8 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -109,14 +109,13 @@ static struct mt9m001 *to_mt9m001(const struct i2c_client *client) static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); + return i2c_smbus_read_word_swapped(client, reg); } static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int reg_set(struct i2c_client *client, const u8 reg, diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 398f96ffd35e..bee65bff46e8 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -139,25 +139,52 @@ #define MT9M111_MAX_HEIGHT 1024 #define MT9M111_MAX_WIDTH 1280 +struct mt9m111_context { + u16 read_mode; + u16 blanking_h; + u16 blanking_v; + u16 reducer_xzoom; + u16 reducer_yzoom; + u16 reducer_xsize; + u16 reducer_ysize; + u16 output_fmt_ctrl2; + u16 control; +}; + +static struct mt9m111_context context_a = { + .read_mode = MT9M111_READ_MODE_A, + .blanking_h = MT9M111_HORIZONTAL_BLANKING_A, + .blanking_v = MT9M111_VERTICAL_BLANKING_A, + .reducer_xzoom = MT9M111_REDUCER_XZOOM_A, + .reducer_yzoom = MT9M111_REDUCER_YZOOM_A, + .reducer_xsize = MT9M111_REDUCER_XSIZE_A, + .reducer_ysize = MT9M111_REDUCER_YSIZE_A, + .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_A, + .control = MT9M111_CTXT_CTRL_RESTART, +}; + +static struct mt9m111_context context_b = { + .read_mode = MT9M111_READ_MODE_B, + .blanking_h = MT9M111_HORIZONTAL_BLANKING_B, + .blanking_v = MT9M111_VERTICAL_BLANKING_B, + .reducer_xzoom = MT9M111_REDUCER_XZOOM_B, + .reducer_yzoom = MT9M111_REDUCER_YZOOM_B, + .reducer_xsize = MT9M111_REDUCER_XSIZE_B, + .reducer_ysize = MT9M111_REDUCER_YSIZE_B, + .output_fmt_ctrl2 = MT9M111_OUTPUT_FORMAT_CTRL2_B, + .control = MT9M111_CTXT_CTRL_RESTART | + MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B | + MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B | + MT9M111_CTXT_CTRL_READ_MODE_B | MT9M111_CTXT_CTRL_VBLANK_SEL_B | + MT9M111_CTXT_CTRL_HBLANK_SEL_B, +}; + /* MT9M111 has only one fixed colorspace per pixelcode */ struct mt9m111_datafmt { enum v4l2_mbus_pixelcode code; enum v4l2_colorspace colorspace; }; -/* Find a data format by a pixel code in an array */ -static const struct mt9m111_datafmt *mt9m111_find_datafmt( - enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, @@ -173,27 +200,35 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, }; -enum mt9m111_context { - HIGHPOWER = 0, - LOWPOWER, -}; - struct mt9m111 { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; struct v4l2_ctrl *gain; int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code * from v4l2-chip-ident.h */ - enum mt9m111_context context; - struct v4l2_rect rect; + struct mt9m111_context *ctx; + struct v4l2_rect rect; /* cropping rectangle */ + int width; /* output */ + int height; /* sizes */ struct mutex power_lock; /* lock to protect power_count */ int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ unsigned char datawidth; - unsigned int powered:1; }; +/* Find a data format by a pixel code */ +static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111, + enum v4l2_mbus_pixelcode code) +{ + int i; + for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++) + if (mt9m111_colour_fmts[i].code == code) + return mt9m111_colour_fmts + i; + + return mt9m111->fmt; +} + static struct mt9m111 *to_mt9m111(const struct i2c_client *client) { return container_of(i2c_get_clientdata(client), struct mt9m111, subdev); @@ -211,7 +246,7 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg) if (page > 2) return -EINVAL; - ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); + ret = i2c_smbus_write_word_swapped(client, MT9M111_PAGE_MAP, page); if (!ret) mt9m111->lastpage = page; return ret; @@ -223,7 +258,7 @@ static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) ret = reg_page_map_set(client, reg); if (!ret) - ret = swab16(i2c_smbus_read_word_data(client, reg & 0xff)); + ret = i2c_smbus_read_word_swapped(client, reg & 0xff); dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); return ret; @@ -236,8 +271,7 @@ static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, ret = reg_page_map_set(client, reg); if (!ret) - ret = i2c_smbus_write_word_data(client, reg & 0xff, - swab16(data)); + ret = i2c_smbus_write_word_swapped(client, reg & 0xff, data); dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); return ret; } @@ -276,76 +310,63 @@ static int mt9m111_reg_mask(struct i2c_client *client, const u16 reg, } static int mt9m111_set_context(struct mt9m111 *mt9m111, - enum mt9m111_context ctxt) + struct mt9m111_context *ctx) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B - | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B - | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B - | MT9M111_CTXT_CTRL_VBLANK_SEL_B - | MT9M111_CTXT_CTRL_HBLANK_SEL_B; - int valA = MT9M111_CTXT_CTRL_RESTART; - - if (ctxt == HIGHPOWER) - return reg_write(CONTEXT_CONTROL, valB); - else - return reg_write(CONTEXT_CONTROL, valA); + return reg_write(CONTEXT_CONTROL, ctx->control); } -static int mt9m111_setup_rect(struct mt9m111 *mt9m111, - struct v4l2_rect *rect) +static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111, + struct mt9m111_context *ctx, struct v4l2_rect *rect, + unsigned int width, unsigned int height) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret, is_raw_format; - int width = rect->width; - int height = rect->height; + int ret = mt9m111_reg_write(client, ctx->reducer_xzoom, rect->width); + if (!ret) + ret = mt9m111_reg_write(client, ctx->reducer_yzoom, rect->height); + if (!ret) + ret = mt9m111_reg_write(client, ctx->reducer_xsize, width); + if (!ret) + ret = mt9m111_reg_write(client, ctx->reducer_ysize, height); + return ret; +} - if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) - is_raw_format = 1; - else - is_raw_format = 0; +static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect, + int width, int height, enum v4l2_mbus_pixelcode code) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + int ret; ret = reg_write(COLUMN_START, rect->left); if (!ret) ret = reg_write(ROW_START, rect->top); - if (is_raw_format) { - if (!ret) - ret = reg_write(WINDOW_WIDTH, width); - if (!ret) - ret = reg_write(WINDOW_HEIGHT, height); - } else { - if (!ret) - ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH); - if (!ret) - ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT); - if (!ret) - ret = reg_write(REDUCER_XSIZE_B, width); - if (!ret) - ret = reg_write(REDUCER_YSIZE_B, height); - if (!ret) - ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH); - if (!ret) - ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT); + if (!ret) + ret = reg_write(WINDOW_WIDTH, rect->width); + if (!ret) + ret = reg_write(WINDOW_HEIGHT, rect->height); + + if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { + /* IFP in use, down-scaling possible */ if (!ret) - ret = reg_write(REDUCER_XSIZE_A, width); + ret = mt9m111_setup_rect_ctx(mt9m111, &context_b, + rect, width, height); if (!ret) - ret = reg_write(REDUCER_YSIZE_A, height); + ret = mt9m111_setup_rect_ctx(mt9m111, &context_a, + rect, width, height); } + dev_dbg(&client->dev, "%s(%x): %ux%u@%u:%u -> %ux%u = %d\n", + __func__, code, rect->width, rect->height, rect->left, rect->top, + width, height, ret); + return ret; } static int mt9m111_enable(struct mt9m111 *mt9m111) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - int ret; - - ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); - if (!ret) - mt9m111->powered = 1; - return ret; + return reg_write(RESET, MT9M111_RESET_CHIP_ENABLE); } static int mt9m111_reset(struct mt9m111 *mt9m111) @@ -363,43 +384,41 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) return ret; } -static int mt9m111_make_rect(struct mt9m111 *mt9m111, - struct v4l2_rect *rect) +static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { + struct v4l2_rect rect = a->c; + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + int width, height; + int ret; + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { /* Bayer format - even size lengths */ - rect->width = ALIGN(rect->width, 2); - rect->height = ALIGN(rect->height, 2); + rect.width = ALIGN(rect.width, 2); + rect.height = ALIGN(rect.height, 2); /* Let the user play with the starting pixel */ } /* FIXME: the datasheet doesn't specify minimum sizes */ - soc_camera_limit_side(&rect->left, &rect->width, + soc_camera_limit_side(&rect.left, &rect.width, MT9M111_MIN_DARK_COLS, 2, MT9M111_MAX_WIDTH); - soc_camera_limit_side(&rect->top, &rect->height, + soc_camera_limit_side(&rect.top, &rect.height, MT9M111_MIN_DARK_ROWS, 2, MT9M111_MAX_HEIGHT); - return mt9m111_setup_rect(mt9m111, rect); -} - -static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) -{ - struct v4l2_rect rect = a->c; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - int ret; - - dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n", - __func__, rect.left, rect.top, rect.width, rect.height); + width = min(mt9m111->width, rect.width); + height = min(mt9m111->height, rect.height); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - ret = mt9m111_make_rect(mt9m111, &rect); - if (!ret) + ret = mt9m111_setup_geometry(mt9m111, &rect, width, height, mt9m111->fmt->code); + if (!ret) { mt9m111->rect = rect; + mt9m111->width = width; + mt9m111->height = height; + } + return ret; } @@ -434,8 +453,8 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd, { struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - mf->width = mt9m111->rect.width; - mf->height = mt9m111->rect.height; + mf->width = mt9m111->width; + mf->height = mt9m111->height; mf->code = mt9m111->fmt->code; mf->colorspace = mt9m111->fmt->colorspace; mf->field = V4L2_FIELD_NONE; @@ -504,46 +523,11 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111, return -EINVAL; } - ret = reg_mask(OUTPUT_FORMAT_CTRL2_A, data_outfmt2, - mask_outfmt2); + ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2, + data_outfmt2, mask_outfmt2); if (!ret) - ret = reg_mask(OUTPUT_FORMAT_CTRL2_B, data_outfmt2, - mask_outfmt2); - - return ret; -} - -static int mt9m111_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct mt9m111_datafmt *fmt; - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - struct v4l2_rect rect = { - .left = mt9m111->rect.left, - .top = mt9m111->rect.top, - .width = mf->width, - .height = mf->height, - }; - int ret; - - fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, - ARRAY_SIZE(mt9m111_colour_fmts)); - if (!fmt) - return -EINVAL; - - dev_dbg(&client->dev, - "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, - mf->code, rect.left, rect.top, rect.width, rect.height); - - ret = mt9m111_make_rect(mt9m111, &rect); - if (!ret) - ret = mt9m111_set_pixfmt(mt9m111, mf->code); - if (!ret) { - mt9m111->rect = rect; - mt9m111->fmt = fmt; - mf->colorspace = fmt->colorspace; - } + ret = mt9m111_reg_mask(client, context_b.output_fmt_ctrl2, + data_outfmt2, mask_outfmt2); return ret; } @@ -551,42 +535,71 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd, static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { + struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); const struct mt9m111_datafmt *fmt; - bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || - mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; - - fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, - ARRAY_SIZE(mt9m111_colour_fmts)); - if (!fmt) { - fmt = mt9m111->fmt; - mf->code = fmt->code; - } + struct v4l2_rect *rect = &mt9m111->rect; + bool bayer; + + fmt = mt9m111_find_datafmt(mt9m111, mf->code); + + bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; /* * With Bayer format enforce even side lengths, but let the user play * with the starting pixel */ + if (bayer) { + rect->width = ALIGN(rect->width, 2); + rect->height = ALIGN(rect->height, 2); + } - if (mf->height > MT9M111_MAX_HEIGHT) - mf->height = MT9M111_MAX_HEIGHT; - else if (mf->height < 2) - mf->height = 2; - else if (bayer) - mf->height = ALIGN(mf->height, 2); + if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { + /* IFP bypass mode, no scaling */ + mf->width = rect->width; + mf->height = rect->height; + } else { + /* No upscaling */ + if (mf->width > rect->width) + mf->width = rect->width; + if (mf->height > rect->height) + mf->height = rect->height; + } - if (mf->width > MT9M111_MAX_WIDTH) - mf->width = MT9M111_MAX_WIDTH; - else if (mf->width < 2) - mf->width = 2; - else if (bayer) - mf->width = ALIGN(mf->width, 2); + dev_dbg(&client->dev, "%s(): %ux%u, code=%x\n", __func__, + mf->width, mf->height, fmt->code); + mf->code = fmt->code; mf->colorspace = fmt->colorspace; return 0; } +static int mt9m111_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct mt9m111_datafmt *fmt; + struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + struct v4l2_rect *rect = &mt9m111->rect; + int ret; + + mt9m111_try_fmt(sd, mf); + fmt = mt9m111_find_datafmt(mt9m111, mf->code); + /* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */ + + ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code); + if (!ret) + ret = mt9m111_set_pixfmt(mt9m111, mf->code); + if (!ret) { + mt9m111->width = mf->width; + mt9m111->height = mf->height; + mt9m111->fmt = fmt; + } + + return ret; +} + static int mt9m111_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) { @@ -650,17 +663,10 @@ static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; - if (mt9m111->context == HIGHPOWER) { - if (flip) - ret = reg_set(READ_MODE_B, mask); - else - ret = reg_clear(READ_MODE_B, mask); - } else { - if (flip) - ret = reg_set(READ_MODE_A, mask); - else - ret = reg_clear(READ_MODE_A, mask); - } + if (flip) + ret = mt9m111_reg_set(client, mt9m111->ctx->read_mode, mask); + else + ret = mt9m111_reg_clear(client, mt9m111->ctx->read_mode, mask); return ret; } @@ -738,30 +744,39 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) static int mt9m111_suspend(struct mt9m111 *mt9m111) { + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + int ret; + v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); - return 0; + ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); + if (!ret) + ret = reg_set(RESET, MT9M111_RESET_RESET_SOC | + MT9M111_RESET_OUTPUT_DISABLE | + MT9M111_RESET_ANALOG_STANDBY); + if (!ret) + ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); + + return ret; } static void mt9m111_restore_state(struct mt9m111 *mt9m111) { - mt9m111_set_context(mt9m111, mt9m111->context); + mt9m111_set_context(mt9m111, mt9m111->ctx); mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); - mt9m111_setup_rect(mt9m111, &mt9m111->rect); + mt9m111_setup_geometry(mt9m111, &mt9m111->rect, + mt9m111->width, mt9m111->height, mt9m111->fmt->code); v4l2_ctrl_handler_setup(&mt9m111->hdl); } static int mt9m111_resume(struct mt9m111 *mt9m111) { - int ret = 0; + int ret = mt9m111_enable(mt9m111); + if (!ret) + ret = mt9m111_reset(mt9m111); + if (!ret) + mt9m111_restore_state(mt9m111); - if (mt9m111->powered) { - ret = mt9m111_enable(mt9m111); - if (!ret) - ret = mt9m111_reset(mt9m111); - if (!ret) - mt9m111_restore_state(mt9m111); - } return ret; } @@ -770,12 +785,13 @@ static int mt9m111_init(struct mt9m111 *mt9m111) struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; - mt9m111->context = HIGHPOWER; + /* Default HIGHPOWER context */ + mt9m111->ctx = &context_b; ret = mt9m111_enable(mt9m111); if (!ret) ret = mt9m111_reset(mt9m111); if (!ret) - ret = mt9m111_set_context(mt9m111, mt9m111->context); + ret = mt9m111_set_context(mt9m111, mt9m111->ctx); if (ret) dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); return ret; diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c index 73c068993f05..93c3ec7426e8 100644 --- a/drivers/media/video/mt9p031.c +++ b/drivers/media/video/mt9p031.c @@ -132,13 +132,12 @@ static struct mt9p031 *to_mt9p031(struct v4l2_subdev *sd) static int mt9p031_read(struct i2c_client *client, u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : be16_to_cpu(data); + return i2c_smbus_read_word_swapped(client, reg); } static int mt9p031_write(struct i2c_client *client, u8 reg, u16 data) { - return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int mt9p031_set_output_control(struct mt9p031 *mt9p031, u16 clear, diff --git a/drivers/media/video/mt9t001.c b/drivers/media/video/mt9t001.c index 08074b8a2736..cd81d04a529e 100644 --- a/drivers/media/video/mt9t001.c +++ b/drivers/media/video/mt9t001.c @@ -133,13 +133,12 @@ static inline struct mt9t001 *to_mt9t001(struct v4l2_subdev *sd) static int mt9t001_read(struct i2c_client *client, u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : be16_to_cpu(data); + return i2c_smbus_read_word_swapped(client, reg); } static int mt9t001_write(struct i2c_client *client, u8 reg, u16 data) { - return i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int mt9t001_set_output_control(struct mt9t001 *mt9t001, u16 clear, diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 0e78477452ff..84add1aef139 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -90,14 +90,13 @@ static struct mt9t031 *to_mt9t031(const struct i2c_client *client) static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); + return i2c_smbus_read_word_swapped(client, reg); } static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int reg_set(struct i2c_client *client, const u8 reg, diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 690ee0d42eeb..944940758fa3 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -130,14 +130,13 @@ static struct mt9v022 *to_mt9v022(const struct i2c_client *client) static int reg_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); - return data < 0 ? data : swab16(data); + return i2c_smbus_read_word_swapped(client, reg); } static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int reg_set(struct i2c_client *client, const u8 reg, diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c index f080c162123f..d90b982cc218 100644 --- a/drivers/media/video/mt9v032.c +++ b/drivers/media/video/mt9v032.c @@ -139,10 +139,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) static int mt9v032_read(struct i2c_client *client, const u8 reg) { - s32 data = i2c_smbus_read_word_data(client, reg); + s32 data = i2c_smbus_read_word_swapped(client, reg); dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__, - swab16(data), reg); - return data < 0 ? data : swab16(data); + data, reg); + return data; } static int mt9v032_write(struct i2c_client *client, const u8 reg, @@ -150,7 +150,7 @@ static int mt9v032_write(struct i2c_client *client, const u8 reg, { dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__, data, reg); - return i2c_smbus_write_word_data(client, reg, swab16(data)); + return i2c_smbus_write_word_swapped(client, reg, data); } static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set) diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 18e94c7d2be8..055d11ddb038 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -487,7 +487,7 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd, return v4l2_subdev_call(sd, video, s_crop, a); } -static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int mx1_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); diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index a803d9ea8fd6..04aab0c538aa 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -210,6 +210,22 @@ #define MAX_VIDEO_MEM 16 +struct mx2_prp_cfg { + int channel; + u32 in_fmt; + u32 out_fmt; + u32 src_pixel; + u32 ch1_pixel; + u32 irq_flags; +}; + +/* prp configuration for a client-host fmt pair */ +struct mx2_fmt_cfg { + enum v4l2_mbus_pixelcode in_fmt; + u32 out_fmt; + struct mx2_prp_cfg cfg; +}; + struct mx2_camera_dev { struct device *dev; struct soc_camera_host soc_host; @@ -241,6 +257,8 @@ struct mx2_camera_dev { void *discard_buffer; dma_addr_t discard_buffer_dma; size_t discard_size; + struct mx2_fmt_cfg *emma_prp; + u32 frame_count; }; /* buffer for one video frame */ @@ -253,6 +271,59 @@ struct mx2_buffer { int bufnum; }; +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 incomming 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, + } + }, + { + .in_fmt = V4L2_MBUS_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, + } + }, +}; + +static struct mx2_fmt_cfg *mx27_emma_prp_get_format( + enum v4l2_mbus_pixelcode 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 mx2_camera_deactivate(struct mx2_camera_dev *pcdev) { unsigned long flags; @@ -301,6 +372,7 @@ static int mx2_camera_add_device(struct soc_camera_device *icd) writel(pcdev->csicr1, pcdev->base_csi + CSICR1); pcdev->icd = icd; + pcdev->frame_count = 0; dev_info(icd->parent, "Camera driver attached to camera %d\n", icd->devnum); @@ -719,55 +791,77 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, 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; + u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; + + if (prp->cfg.channel == 1) { + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB1_PTR); + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_RGB2_PTR); + + 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); + + writel((icd->user_width << 16) | icd->user_height, + pcdev->base_emma + PRP_SRC_FRAME_SIZE); + 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.src_pixel, + pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); + writel(prp->cfg.ch1_pixel, + pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); + } else { /* channel 2 */ + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_DEST_Y_PTR); + writel(pcdev->discard_buffer_dma, + pcdev->base_emma + PRP_SOURCE_Y_PTR); + + if (prp->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { + writel(pcdev->discard_buffer_dma + imgsize, + pcdev->base_emma + PRP_DEST_CB_PTR); + writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), + pcdev->base_emma + PRP_DEST_CR_PTR); + writel(pcdev->discard_buffer_dma + imgsize, + pcdev->base_emma + PRP_SOURCE_CB_PTR); + writel(pcdev->discard_buffer_dma + ((5 * imgsize) / 4), + pcdev->base_emma + PRP_SOURCE_CR_PTR); + } - writel(pcdev->discard_buffer_dma, - pcdev->base_emma + PRP_DEST_RGB1_PTR); - writel(pcdev->discard_buffer_dma, - pcdev->base_emma + PRP_DEST_RGB2_PTR); - - /* - * We only use the EMMA engine to get rid of the broken - * DMA Engine. No color space consversion at the moment. - * We set the incomming and outgoing pixelformat to an - * 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. - */ - writel(PRP_CNTL_CH1EN | + writel(PRP_CNTL_CH2EN | PRP_CNTL_CSIEN | - PRP_CNTL_DATA_IN_RGB16 | - PRP_CNTL_CH1_OUT_RGB16 | - PRP_CNTL_CH1_LEN | - PRP_CNTL_CH1BYP | - PRP_CNTL_CH1_TSKIP(0) | + 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); - writel(((bytesperline >> 1) << 16) | icd->user_height, + writel((icd->user_width << 16) | icd->user_height, pcdev->base_emma + PRP_SRC_FRAME_SIZE); - writel(((bytesperline >> 1) << 16) | icd->user_height, - pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); - writel(bytesperline, - pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); - writel(0x2ca00565, /* RGB565 */ + + writel((icd->user_width << 16) | icd->user_height, + pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); + + writel(prp->cfg.src_pixel, pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); - writel(0x2ca00565, /* RGB565 */ - pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); + + } /* Enable interrupts */ - writel(PRP_INTR_RDERR | - PRP_INTR_CH1WERR | - PRP_INTR_CH2WERR | - PRP_INTR_CH1FC | - PRP_INTR_CH2FC | - PRP_INTR_LBOVF | - PRP_INTR_CH2OVF, - pcdev->base_emma + PRP_INTR_CNTL); + writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); } -static int mx2_camera_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) +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); @@ -911,9 +1005,58 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, 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; + enum v4l2_mbus_pixelcode code; + int ret, formats = 0; + + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* no more formats */ + return 0; + + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + return 0; + } + + if (code == V4L2_MBUS_FMT_YUYV8_2X8) { + formats++; + if (xlate) { + /* + * CH2 can output YUV420 which is a standard format in + * soc_mediabus.c + */ + xlate->host_fmt = + soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8); + xlate->code = code; + dev_dbg(dev, "Providing host format %s for sensor code %d\n", + xlate->host_fmt->name, code); + xlate++; + } + } + + /* Generic pass-trough */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + xlate++; + } + return formats; +} + 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; @@ -946,6 +1089,10 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, pix->colorspace = mf.colorspace; icd->current_fmt = xlate; + if (mx27_camera_emma(pcdev)) + pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, + xlate->host_fmt->fourcc); + return 0; } @@ -1011,7 +1158,12 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, if (mf.field == V4L2_FIELD_ANY) mf.field = V4L2_FIELD_NONE; - if (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; @@ -1173,6 +1325,7 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = { .remove = mx2_camera_remove_device, .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_videobuf = mx2_camera_init_videobuf, .reqbufs = mx2_camera_reqbufs, @@ -1184,6 +1337,8 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = { static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, int bufnum, int state) { + u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width; + struct mx2_fmt_cfg *prp = pcdev->emma_prp; struct mx2_buffer *buf; struct videobuf_buffer *vb; unsigned long phys; @@ -1197,12 +1352,22 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, vb = &buf->vb; #ifdef DEBUG phys = videobuf_to_dma_contig(vb); - if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum) - != phys) { - dev_err(pcdev->dev, "%p != %p\n", phys, - readl(pcdev->base_emma + - PRP_DEST_RGB1_PTR + - 4 * bufnum)); + if (prp->cfg.channel == 1) { + if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + + 4 * bufnum) != phys) { + dev_err(pcdev->dev, "%p != %p\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, "%p != %p\n", phys, + readl(pcdev->base_emma + + PRP_DEST_Y_PTR - + 0x14 * bufnum)); + } } #endif dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, @@ -1211,14 +1376,29 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, list_del(&vb->queue); vb->state = state; do_gettimeofday(&vb->ts); - vb->field_count++; + vb->field_count = pcdev->frame_count * 2; + pcdev->frame_count++; wake_up(&vb->done); } if (list_empty(&pcdev->capture)) { - writel(pcdev->discard_buffer_dma, pcdev->base_emma + - PRP_DEST_RGB1_PTR + 4 * bufnum); + if (prp->cfg.channel == 1) { + writel(pcdev->discard_buffer_dma, pcdev->base_emma + + PRP_DEST_RGB1_PTR + 4 * bufnum); + } else { + writel(pcdev->discard_buffer_dma, pcdev->base_emma + + PRP_DEST_Y_PTR - + 0x14 * bufnum); + if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { + writel(pcdev->discard_buffer_dma + imgsize, + pcdev->base_emma + PRP_DEST_CB_PTR - + 0x14 * bufnum); + writel(pcdev->discard_buffer_dma + + ((5 * imgsize) / 4), pcdev->base_emma + + PRP_DEST_CR_PTR - 0x14 * bufnum); + } + } return; } @@ -1233,7 +1413,18 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, vb->state = VIDEOBUF_ACTIVE; phys = videobuf_to_dma_contig(vb); - writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum); + 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->cfg.out_fmt == PRP_CNTL_CH2_OUT_YUV420) { + 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 irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) @@ -1253,10 +1444,12 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) * the next one. */ cntl = readl(pcdev->base_emma + PRP_CNTL); - writel(cntl & ~PRP_CNTL_CH1EN, 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); } - if ((status & (3 << 5)) == (3 << 5) + if ((((status & (3 << 5)) == (3 << 5)) || + ((status & (3 << 3)) == (3 << 3))) && !list_empty(&pcdev->active_bufs)) { /* * Both buffers have triggered, process the one we're expecting @@ -1267,9 +1460,9 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE); status &= ~(1 << (6 - buf->bufnum)); /* mark processed */ } - if (status & (1 << 6)) + if ((status & (1 << 6)) || (status & (1 << 4))) mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE); - if (status & (1 << 5)) + if ((status & (1 << 5)) || (status & (1 << 3))) mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE); writel(status, pcdev->base_emma + PRP_INTRSTATUS); diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index f96f92f00f92..0cb461dd396a 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -982,12 +982,13 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, return 0; } -static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +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; @@ -1285,19 +1286,7 @@ static struct platform_driver mx3_camera_driver = { .remove = __devexit_p(mx3_camera_remove), }; - -static int __init mx3_camera_init(void) -{ - return platform_driver_register(&mx3_camera_driver); -} - -static void __exit mx3_camera_exit(void) -{ - platform_driver_unregister(&mx3_camera_driver); -} - -module_init(mx3_camera_init); -module_exit(mx3_camera_exit); +module_platform_driver(mx3_camera_driver); MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index ee0d0b39cd17..a277f95091ef 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -70,9 +70,9 @@ static u32 video1_numbuffers = 3; static u32 video2_numbuffers = 3; static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE; static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE; -static u32 vid1_static_vrfb_alloc; -static u32 vid2_static_vrfb_alloc; -static int debug; +static bool vid1_static_vrfb_alloc; +static bool vid2_static_vrfb_alloc; +static bool debug; /* Module parameters */ module_param(video1_numbuffers, uint, S_IRUGO); @@ -424,7 +424,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n" "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" "out_height=%d rotation_type=%d screen_width=%d\n", - __func__, info.enabled, info.paddr, info.width, info.height, + __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height, info.color_mode, info.rotation, info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height, info.rotation_type, info.screen_width); @@ -524,10 +524,50 @@ static int omapvid_apply_changes(struct omap_vout_device *vout) return 0; } +static int omapvid_handle_interlace_display(struct omap_vout_device *vout, + unsigned int irqstatus, struct timeval timevalue) +{ + u32 fid; + + if (vout->first_int) { + vout->first_int = 0; + goto err; + } + + if (irqstatus & DISPC_IRQ_EVSYNC_ODD) + fid = 1; + else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) + fid = 0; + else + goto err; + + vout->field_id ^= 1; + if (fid != vout->field_id) { + if (fid == 0) + vout->field_id = fid; + } else if (0 == fid) { + if (vout->cur_frm == vout->next_frm) + goto err; + + vout->cur_frm->ts = timevalue; + vout->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm = vout->next_frm; + } else { + if (list_empty(&vout->dma_queue) || + (vout->cur_frm != vout->next_frm)) + goto err; + } + + return vout->field_id; +err: + return 0; +} + static void omap_vout_isr(void *arg, unsigned int irqstatus) { - int ret; - u32 addr, fid; + int ret, fid, mgr_id; + u32 addr, irq; struct omap_overlay *ovl; struct timeval timevalue; struct omapvideo_info *ovid; @@ -543,112 +583,73 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) if (!ovl->manager || !ovl->manager->device) return; + mgr_id = ovl->manager->id; cur_display = ovl->manager->device; spin_lock(&vout->vbq_lock); do_gettimeofday(&timevalue); - if (cur_display->type != OMAP_DISPLAY_TYPE_VENC) { - switch (cur_display->type) { - case OMAP_DISPLAY_TYPE_DPI: - if (!(irqstatus & (DISPC_IRQ_VSYNC | DISPC_IRQ_VSYNC2))) - goto vout_isr_err; - break; - case OMAP_DISPLAY_TYPE_HDMI: - if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) - goto vout_isr_err; - break; - default: - goto vout_isr_err; - } - if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { - vout->cur_frm->ts = timevalue; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); - vout->cur_frm = vout->next_frm; - } - vout->first_int = 0; - if (list_empty(&vout->dma_queue)) + switch (cur_display->type) { + case OMAP_DISPLAY_TYPE_DSI: + case OMAP_DISPLAY_TYPE_DPI: + if (mgr_id == OMAP_DSS_CHANNEL_LCD) + irq = DISPC_IRQ_VSYNC; + else if (mgr_id == OMAP_DSS_CHANNEL_LCD2) + irq = DISPC_IRQ_VSYNC2; + else goto vout_isr_err; - vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vout->next_frm->queue); - - vout->next_frm->state = VIDEOBUF_ACTIVE; + if (!(irqstatus & irq)) + goto vout_isr_err; + break; + case OMAP_DISPLAY_TYPE_VENC: + fid = omapvid_handle_interlace_display(vout, irqstatus, + timevalue); + if (!fid) + goto vout_isr_err; + break; + case OMAP_DISPLAY_TYPE_HDMI: + if (!(irqstatus & DISPC_IRQ_EVSYNC_EVEN)) + goto vout_isr_err; + break; + default: + goto vout_isr_err; + } - addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] - + vout->cropped_offset; + if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { + vout->cur_frm->ts = timevalue; + vout->cur_frm->state = VIDEOBUF_DONE; + wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm = vout->next_frm; + } - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - printk(KERN_ERR VOUT_NAME "failed to change mode\n"); - } else { + vout->first_int = 0; + if (list_empty(&vout->dma_queue)) + goto vout_isr_err; - if (vout->first_int) { - vout->first_int = 0; - goto vout_isr_err; - } - if (irqstatus & DISPC_IRQ_EVSYNC_ODD) - fid = 1; - else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) - fid = 0; - else - goto vout_isr_err; + vout->next_frm = list_entry(vout->dma_queue.next, + struct videobuf_buffer, queue); + list_del(&vout->next_frm->queue); - vout->field_id ^= 1; - if (fid != vout->field_id) { - if (0 == fid) - vout->field_id = fid; + vout->next_frm->state = VIDEOBUF_ACTIVE; - goto vout_isr_err; - } - if (0 == fid) { - if (vout->cur_frm == vout->next_frm) - goto vout_isr_err; - - vout->cur_frm->ts = timevalue; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); - vout->cur_frm = vout->next_frm; - } else if (1 == fid) { - if (list_empty(&vout->dma_queue) || - (vout->cur_frm != vout->next_frm)) - goto vout_isr_err; - - vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); - list_del(&vout->next_frm->queue); - - vout->next_frm->state = VIDEOBUF_ACTIVE; - addr = (unsigned long) - vout->queued_buf_addr[vout->next_frm->i] + - vout->cropped_offset; - /* First save the configuration in ovelray structure */ - ret = omapvid_init(vout, addr); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to set overlay info\n"); - /* Enable the pipeline and set the Go bit */ - ret = omapvid_apply_changes(vout); - if (ret) - printk(KERN_ERR VOUT_NAME - "failed to change mode\n"); - } + addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] + + vout->cropped_offset; - } + /* First save the configuration in ovelray structure */ + ret = omapvid_init(vout, addr); + if (ret) + printk(KERN_ERR VOUT_NAME + "failed to set overlay info\n"); + /* Enable the pipeline and set the Go bit */ + ret = omapvid_apply_changes(vout); + if (ret) + printk(KERN_ERR VOUT_NAME "failed to change mode\n"); vout_isr_err: spin_unlock(&vout->vbq_lock); } - /* Video buffer call backs */ /* @@ -664,10 +665,14 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, u32 phy_addr = 0, virt_addr = 0; struct omap_vout_device *vout = q->priv_data; struct omapvideo_info *ovid = &vout->vid_info; + int vid_max_buf_size; if (!vout) return -EINVAL; + vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize : + video2_bufsize; + if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) return -EINVAL; @@ -690,7 +695,7 @@ static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, video1_numbuffers : video2_numbuffers; /* Check the size of the buffer */ - if (*size > vout->buffer_size) { + if (*size > vid_max_buf_size) { v4l2_err(&vout->vid_dev->v4l2_dev, "buffer allocation mismatch [%u] [%u]\n", *size, vout->buffer_size); @@ -943,12 +948,8 @@ static int omap_vout_release(struct file *file) /* Disable all the overlay managers connected with this interface */ for (i = 0; i < ovid->num_overlays; i++) { struct omap_overlay *ovl = ovid->overlays[i]; - if (ovl->manager && ovl->manager->device) { - struct omap_overlay_info info; - ovl->get_overlay_info(ovl, &info); - info.enabled = 0; - ovl->set_overlay_info(ovl, &info); - } + if (ovl->manager && ovl->manager->device) + ovl->disable(ovl); } /* Turn off the pipeline */ ret = omapvid_apply_changes(vout); @@ -1668,7 +1669,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) if (ovl->manager && ovl->manager->device) { struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); - info.enabled = 1; info.paddr = addr; if (ovl->set_overlay_info(ovl, &info)) { ret = -EINVAL; @@ -1687,6 +1687,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) if (ret) v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); + for (j = 0; j < ovid->num_overlays; j++) { + struct omap_overlay *ovl = ovid->overlays[j]; + + if (ovl->manager && ovl->manager->device) { + ret = ovl->enable(ovl); + if (ret) + goto streamon_err1; + } + } + ret = 0; streamon_err1: @@ -1716,16 +1726,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; - if (ovl->manager && ovl->manager->device) { - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - info.enabled = 0; - ret = ovl->set_overlay_info(ovl, &info); - if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, - "failed to update overlay info in streamoff\n"); - } + if (ovl->manager && ovl->manager->device) + ovl->disable(ovl); } /* Turn of the pipeline */ diff --git a/drivers/media/video/omap/omap_vout_vrfb.c b/drivers/media/video/omap/omap_vout_vrfb.c index ebebcac49225..4be26abf6cea 100644 --- a/drivers/media/video/omap/omap_vout_vrfb.c +++ b/drivers/media/video/omap/omap_vout_vrfb.c @@ -84,7 +84,7 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) } int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, - u32 static_vrfb_allocation) + bool static_vrfb_allocation) { int ret = 0, i, j; struct omap_vout_device *vout; diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h index d793501cafcc..27a95d23b913 100644 --- a/drivers/media/video/omap/omap_voutdef.h +++ b/drivers/media/video/omap/omap_voutdef.h @@ -25,7 +25,7 @@ #define MAC_VRFB_CTXS 4 #define MAX_VOUT_DEV 2 #define MAX_OVLS 3 -#define MAX_DISPLAYS 3 +#define MAX_DISPLAYS 10 #define MAX_MANAGERS 3 #define QQVGA_WIDTH 160 diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 6a6cf388bae4..c20f5ecd6790 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -1436,13 +1436,13 @@ static int omap1_cam_querycap(struct soc_camera_host *ici, return 0; } -static int omap1_cam_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) +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,}; @@ -1713,17 +1713,7 @@ static struct platform_driver omap1_cam_driver = { .remove = __exit_p(omap1_cam_remove), }; -static int __init omap1_cam_init(void) -{ - return platform_driver_register(&omap1_cam_driver); -} -module_init(omap1_cam_init); - -static void __exit omap1_cam_exit(void) -{ - platform_driver_unregister(&omap1_cam_driver); -} -module_exit(omap1_cam_exit); +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"); diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 45522e603185..7d3864144368 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -1868,21 +1868,7 @@ static struct platform_driver omap24xxcam_driver = { }, }; -/* - * - * Module initialisation and deinitialisation - * - */ - -static int __init omap24xxcam_init(void) -{ - return platform_driver_register(&omap24xxcam_driver); -} - -static void __exit omap24xxcam_cleanup(void) -{ - platform_driver_unregister(&omap24xxcam_driver); -} +module_platform_driver(omap24xxcam_driver); MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver"); @@ -1894,6 +1880,3 @@ MODULE_PARM_DESC(video_nr, module_param(capture_mem, int, 0); MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture " "buffers (default 4800kiB)"); - -module_init(omap24xxcam_init); -module_exit(omap24xxcam_cleanup); diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index d4c48ef227fb..12d5f923e1d0 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -403,6 +403,7 @@ static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus) static void isp_isr_sbl(struct isp_device *isp) { struct device *dev = isp->dev; + struct isp_pipeline *pipe; u32 sbl_pcr; /* @@ -416,27 +417,38 @@ static void isp_isr_sbl(struct isp_device *isp) if (sbl_pcr) dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr); - if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF - | ISPSBL_PCR_CSIB_WBL_OVF)) { - isp->isp_ccdc.error = 1; - if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) - isp->isp_prev.error = 1; - if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER) - isp->isp_res.error = 1; + if (sbl_pcr & ISPSBL_PCR_CSIB_WBL_OVF) { + pipe = to_isp_pipeline(&isp->isp_ccp2.subdev.entity); + if (pipe != NULL) + pipe->error = true; + } + + if (sbl_pcr & ISPSBL_PCR_CSIA_WBL_OVF) { + pipe = to_isp_pipeline(&isp->isp_csi2a.subdev.entity); + if (pipe != NULL) + pipe->error = true; + } + + if (sbl_pcr & ISPSBL_PCR_CCDC_WBL_OVF) { + pipe = to_isp_pipeline(&isp->isp_ccdc.subdev.entity); + if (pipe != NULL) + pipe->error = true; } if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) { - isp->isp_prev.error = 1; - if (isp->isp_res.input == RESIZER_INPUT_VP && - !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)) - isp->isp_res.error = 1; + pipe = to_isp_pipeline(&isp->isp_prev.subdev.entity); + if (pipe != NULL) + pipe->error = true; } if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF | ISPSBL_PCR_RSZ2_WBL_OVF | ISPSBL_PCR_RSZ3_WBL_OVF - | ISPSBL_PCR_RSZ4_WBL_OVF)) - isp->isp_res.error = 1; + | ISPSBL_PCR_RSZ4_WBL_OVF)) { + pipe = to_isp_pipeline(&isp->isp_res.subdev.entity); + if (pipe != NULL) + pipe->error = true; + } if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF) omap3isp_stat_sbl_overflow(&isp->isp_af); @@ -464,24 +476,17 @@ static irqreturn_t isp_isr(int irq, void *_isp) IRQ0STATUS_HS_VS_IRQ; struct isp_device *isp = _isp; u32 irqstatus; - int ret; irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_isr_sbl(isp); - if (irqstatus & IRQ0STATUS_CSIA_IRQ) { - ret = omap3isp_csi2_isr(&isp->isp_csi2a); - if (ret) - isp->isp_ccdc.error = 1; - } + if (irqstatus & IRQ0STATUS_CSIA_IRQ) + omap3isp_csi2_isr(&isp->isp_csi2a); - if (irqstatus & IRQ0STATUS_CSIB_IRQ) { - ret = omap3isp_ccp2_isr(&isp->isp_ccp2); - if (ret) - isp->isp_ccdc.error = 1; - } + if (irqstatus & IRQ0STATUS_CSIB_IRQ) + omap3isp_ccp2_isr(&isp->isp_ccp2); if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) { if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) @@ -2222,24 +2227,7 @@ static struct platform_driver omap3isp_driver = { }, }; -/* - * isp_init - ISP module initialization. - */ -static int __init isp_init(void) -{ - return platform_driver_register(&omap3isp_driver); -} - -/* - * isp_cleanup - ISP module cleanup. - */ -static void __exit isp_cleanup(void) -{ - platform_driver_unregister(&omap3isp_driver); -} - -module_init(isp_init); -module_exit(isp_cleanup); +module_platform_driver(omap3isp_driver); MODULE_AUTHOR("Nokia Corporation"); MODULE_DESCRIPTION("TI OMAP3 ISP driver"); diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index d341ba12593f..a74a79701d34 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1406,9 +1406,8 @@ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) { - struct isp_pipeline *pipe = - to_isp_pipeline(&ccdc->video_out.video.entity); - struct video_device *vdev = ccdc->subdev.devnode; + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct video_device *vdev = &ccdc->subdev.devnode; struct v4l2_event event; memset(&event, 0, sizeof(event)); @@ -1428,8 +1427,11 @@ static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) unsigned long flags; if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccdc->subdev.entity); + ccdc_lsc_error_handler(ccdc); - ccdc->error = 1; + pipe->error = true; dev_dbg(to_device(ccdc), "lsc prefetch error\n"); } @@ -1504,7 +1506,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) goto done; } - buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error); + buffer = omap3isp_video_buffer_next(&ccdc->video_out); if (buffer != NULL) { ccdc_set_outaddr(ccdc, buffer->isp_addr); restart = 1; @@ -1518,7 +1520,6 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) ISP_PIPELINE_STREAM_SINGLESHOT); done: - ccdc->error = 0; return restart; } @@ -1744,7 +1745,6 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) */ ccdc_config_vp(ccdc); ccdc_enable_vp(ccdc, 1); - ccdc->error = 0; ccdc_print_status(ccdc); } diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h index 483a19cac1ad..6d0264bab75b 100644 --- a/drivers/media/video/omap3isp/ispccdc.h +++ b/drivers/media/video/omap3isp/ispccdc.h @@ -150,7 +150,6 @@ struct ispccdc_lsc { * @input: Active input * @output: Active outputs * @video_out: Output video node - * @error: A hardware error occurred during capture * @alaw: A-law compression enabled (1) or disabled (0) * @lpf: Low pass filter enabled (1) or disabled (0) * @obclamp: Optical-black clamp enabled (1) or disabled (0) @@ -178,7 +177,6 @@ struct isp_ccdc_device { enum ccdc_input_entity input; unsigned int output; struct isp_video video_out; - unsigned int error; unsigned int alaw:1, lpf:1, diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index 904ca8c8b17f..70ddbf35b223 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -556,7 +556,7 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); struct isp_buffer *buffer; - buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error); + buffer = omap3isp_video_buffer_next(&ccp2->video_in); if (buffer != NULL) ccp2_set_inaddr(ccp2, buffer->isp_addr); @@ -567,8 +567,6 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_SINGLESHOT); } - - ccp2->error = 0; } /* @@ -576,13 +574,11 @@ static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) * @ccp2: Pointer to ISP CCP2 device * * This will handle the CCP2 interrupts - * - * Returns -EIO in case of error, or 0 on success. */ -int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) +void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) { + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); struct isp_device *isp = to_isp_device(ccp2); - int ret = 0; static const u32 ISPCCP2_LC01_ERROR = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | @@ -604,19 +600,18 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) ISPCCP2_LCM_IRQSTATUS); /* Errors */ if (lcx_irqstatus & ISPCCP2_LC01_ERROR) { - ccp2->error = 1; + pipe->error = true; dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus); - return -EIO; + return; } if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) { - ccp2->error = 1; + pipe->error = true; dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus); - ret = -EIO; } if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping)) - return 0; + return; /* Frame number propagation */ if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) { @@ -629,8 +624,6 @@ int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) /* Handle queued buffers on frame end interrupts */ if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ) ccp2_isr_buffer(ccp2); - - return ret; } /* ----------------------------------------------------------------------------- @@ -867,7 +860,6 @@ static int ccp2_s_stream(struct v4l2_subdev *sd, int enable) if (enable == ISP_PIPELINE_STREAM_STOPPED) return 0; atomic_set(&ccp2->stopping, 0); - ccp2->error = 0; } switch (enable) { diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/video/omap3isp/ispccp2.h index 6674e9de2cd7..76d65f4576ef 100644 --- a/drivers/media/video/omap3isp/ispccp2.h +++ b/drivers/media/video/omap3isp/ispccp2.h @@ -82,7 +82,6 @@ struct isp_ccp2_device { struct isp_video video_in; struct isp_csiphy *phy; struct regulator *vdds_csib; - unsigned int error; enum isp_pipeline_stream_state state; wait_queue_head_t wait; atomic_t stopping; @@ -94,6 +93,6 @@ void omap3isp_ccp2_cleanup(struct isp_device *isp); int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, struct v4l2_device *vdev); void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2); -int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); +void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); #endif /* OMAP3_ISP_CCP2_H */ diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 0c5f1cb9d99d..fcb5168996a7 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -667,7 +667,7 @@ static void csi2_isr_buffer(struct isp_csi2_device *csi2) csi2_ctx_enable(isp, csi2, 0, 0); - buffer = omap3isp_video_buffer_next(&csi2->video_out, 0); + buffer = omap3isp_video_buffer_next(&csi2->video_out); /* * Let video queue operation restart engine if there is an underrun @@ -727,17 +727,15 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2, /* * omap3isp_csi2_isr - CSI2 interrupt handling. - * - * Return -EIO on Transmission error */ -int omap3isp_csi2_isr(struct isp_csi2_device *csi2) +void omap3isp_csi2_isr(struct isp_csi2_device *csi2) { + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); u32 csi2_irqstatus, cpxio1_irqstatus; struct isp_device *isp = csi2->isp; - int retval = 0; if (!csi2->available) - return -ENODEV; + return; csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); @@ -750,7 +748,7 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2) csi2->regs1, ISPCSI2_PHY_IRQSTATUS); dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " "%x\n", cpxio1_irqstatus); - retval = -EIO; + pipe->error = true; } if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | @@ -775,11 +773,11 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2) ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); - retval = -EIO; + pipe->error = true; } if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) - return 0; + return; /* Successful cases */ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) @@ -787,8 +785,6 @@ int omap3isp_csi2_isr(struct isp_csi2_device *csi2) if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) dev_dbg(isp->dev, "CSI2: ECC correction done\n"); - - return retval; } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h index 456fb7fb8a0f..885ad79a7678 100644 --- a/drivers/media/video/omap3isp/ispcsi2.h +++ b/drivers/media/video/omap3isp/ispcsi2.h @@ -156,7 +156,7 @@ struct isp_csi2_device { atomic_t stopping; }; -int omap3isp_csi2_isr(struct isp_csi2_device *csi2); +void omap3isp_csi2_isr(struct isp_csi2_device *csi2); int omap3isp_csi2_reset(struct isp_csi2_device *csi2); int omap3isp_csi2_init(struct isp_device *isp); void omap3isp_csi2_cleanup(struct isp_device *isp); diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index ccb876fe023f..6d0fb2c8c26d 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -116,11 +116,11 @@ static struct omap3isp_prev_csc flr_prev_csc = { #define PREV_MIN_IN_HEIGHT 8 #define PREV_MAX_IN_HEIGHT 16384 -#define PREV_MIN_OUT_WIDTH 0 -#define PREV_MIN_OUT_HEIGHT 0 -#define PREV_MAX_OUT_WIDTH 1280 -#define PREV_MAX_OUT_WIDTH_ES2 3300 -#define PREV_MAX_OUT_WIDTH_3630 4096 +#define PREV_MIN_OUT_WIDTH 0 +#define PREV_MIN_OUT_HEIGHT 0 +#define PREV_MAX_OUT_WIDTH_REV_1 1280 +#define PREV_MAX_OUT_WIDTH_REV_2 3300 +#define PREV_MAX_OUT_WIDTH_REV_15 4096 /* * Coeficient Tables for the submodules in Preview. @@ -1306,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) switch (isp->revision) { case ISP_REVISION_1_0: - return PREV_MAX_OUT_WIDTH; + return PREV_MAX_OUT_WIDTH_REV_1; case ISP_REVISION_2_0: default: - return PREV_MAX_OUT_WIDTH_ES2; + return PREV_MAX_OUT_WIDTH_REV_2; case ISP_REVISION_15_0: - return PREV_MAX_OUT_WIDTH_3630; + return PREV_MAX_OUT_WIDTH_REV_15; } } @@ -1404,16 +1404,14 @@ static void preview_isr_buffer(struct isp_prev_device *prev) int restart = 0; if (prev->input == PREVIEW_INPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&prev->video_in, - prev->error); + buffer = omap3isp_video_buffer_next(&prev->video_in); if (buffer != NULL) preview_set_inaddr(prev, buffer->isp_addr); pipe->state |= ISP_PIPELINE_IDLE_INPUT; } if (prev->output & PREVIEW_OUTPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&prev->video_out, - prev->error); + buffer = omap3isp_video_buffer_next(&prev->video_out); if (buffer != NULL) { preview_set_outaddr(prev, buffer->isp_addr); restart = 1; @@ -1440,8 +1438,6 @@ static void preview_isr_buffer(struct isp_prev_device *prev) default: return; } - - prev->error = 0; } /* @@ -1565,7 +1561,6 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable) omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW); preview_configure(prev); atomic_set(&prev->stopping, 0); - prev->error = 0; preview_print_status(prev); } diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index f54e775c2df4..09686607973c 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -157,7 +157,6 @@ struct isptables_update { * @output: Bitmask of the active output * @video_in: Input video entity * @video_out: Output video entity - * @error: A hardware error occurred during capture * @params: Module configuration data * @shadow_update: If set, update the hardware configured in the next interrupt * @underrun: Whether the preview entity has queued buffers on the output @@ -179,7 +178,6 @@ struct isp_prev_device { unsigned int output; struct isp_video video_in; struct isp_video video_out; - unsigned int error; struct prev_params params; unsigned int shadow_update:1; diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 50e593bfcfaf..6958a9e3dc22 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -1038,7 +1038,7 @@ static void resizer_isr_buffer(struct isp_res_device *res) /* Complete the output buffer and, if reading from memory, the input * buffer. */ - buffer = omap3isp_video_buffer_next(&res->video_out, res->error); + buffer = omap3isp_video_buffer_next(&res->video_out); if (buffer != NULL) { resizer_set_outaddr(res, buffer->isp_addr); restart = 1; @@ -1047,7 +1047,7 @@ static void resizer_isr_buffer(struct isp_res_device *res) pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; if (res->input == RESIZER_INPUT_MEMORY) { - buffer = omap3isp_video_buffer_next(&res->video_in, 0); + buffer = omap3isp_video_buffer_next(&res->video_in); if (buffer != NULL) resizer_set_inaddr(res, buffer->isp_addr); pipe->state |= ISP_PIPELINE_IDLE_INPUT; @@ -1064,8 +1064,6 @@ static void resizer_isr_buffer(struct isp_res_device *res) if (restart) resizer_enable_oneshot(res); } - - res->error = 0; } /* @@ -1154,7 +1152,6 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER); resizer_configure(res); - res->error = 0; resizer_print_status(res); } diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/video/omap3isp/ispresizer.h index 76abc2e42126..70c1c0e1bbdf 100644 --- a/drivers/media/video/omap3isp/ispresizer.h +++ b/drivers/media/video/omap3isp/ispresizer.h @@ -107,7 +107,6 @@ struct isp_res_device { enum resizer_input_entity input; struct isp_video video_in; struct isp_video video_out; - unsigned int error; u32 addr_base; /* stored source buffer address in memory mode */ u32 crop_offset; /* additional offset for crop in memory mode */ diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index bd3aebafafa0..b02070057724 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -211,14 +211,14 @@ static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix, mbus->width = pix->width; mbus->height = pix->height; - for (i = 0; i < ARRAY_SIZE(formats); ++i) { + /* Skip the last format in the loop so that it will be selected if no + * match is found. + */ + for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { if (formats[i].pixelformat == pix->pixelformat) break; } - if (WARN_ON(i == ARRAY_SIZE(formats))) - return; - mbus->code = formats[i].code; mbus->colorspace = pix->colorspace; mbus->field = pix->field; @@ -581,21 +581,20 @@ static const struct isp_video_queue_operations isp_video_queue_ops = { /* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object - * @error: Whether an error occurred during capture * * Remove the current video buffer from the DMA queue and fill its timestamp, * field count and state fields before waking up its completion handler. * - * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0) - * or VIDEOBUF_ERROR otherwise (@error is non-zero). + * For capture video nodes the buffer state is set to ISP_BUF_STATE_DONE if no + * error has been flagged in the pipeline, or to ISP_BUF_STATE_ERROR otherwise. + * For video output nodes the buffer state is always set to ISP_BUF_STATE_DONE. * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ -struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, - unsigned int error) +struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) { struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); struct isp_video_queue *queue = video->queue; @@ -630,7 +629,13 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, else buf->vbuf.sequence = atomic_read(&pipe->frame_number); - buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE; + /* Report pipeline errors to userspace on the capture device side. */ + if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->error) { + buf->state = ISP_BUF_STATE_ERROR; + pipe->error = false; + } else { + buf->state = ISP_BUF_STATE_DONE; + } wake_up(&buf->wait); @@ -1016,6 +1021,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) if (ret < 0) goto error; + pipe->error = false; + spin_lock_irqsave(&pipe->lock, flags); pipe->state &= ~ISP_PIPELINE_STREAM; pipe->state |= state; diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 08cbfa144e6e..d91bdb919be0 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -85,6 +85,10 @@ enum isp_pipeline_state { ISP_PIPELINE_STREAM = 64, }; +/* + * struct isp_pipeline - An ISP hardware pipeline + * @error: A hardware error occurred during capture + */ struct isp_pipeline { struct media_pipeline pipe; spinlock_t lock; /* Pipeline state and queue flags */ @@ -96,6 +100,7 @@ struct isp_pipeline { unsigned int max_rate; atomic_t frame_number; bool do_propagation; /* of frame number */ + bool error; struct v4l2_fract max_timeperframe; }; @@ -194,8 +199,7 @@ void omap3isp_video_cleanup(struct isp_video *video); int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev); void omap3isp_video_unregister(struct isp_video *video); -struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, - unsigned int error); +struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video); void omap3isp_video_resume(struct isp_video *video, int continuous); struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 8aa058531280..6a564964853a 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -25,7 +25,7 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 122b45760f0d..ebc2c7e39233 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2546,8 +2546,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, } /* Define and configure additional controls from cx2341x module. */ - hdw->mpeg_ctrl_info = kzalloc( - sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL); + hdw->mpeg_ctrl_info = kcalloc(MPEGDEF_COUNT, + sizeof(*(hdw->mpeg_ctrl_info)), + GFP_KERNEL); if (!hdw->mpeg_ctrl_info) goto fail; for (idx = 0; idx < MPEGDEF_COUNT; idx++) { cptr = hdw->controls + idx + CTRLDEF_COUNT; diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 3977addf3ba8..905d41d90c6a 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c @@ -102,8 +102,6 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = #include "pwc-nala.h" }; -static void pwc_set_image_buffer_size(struct pwc_device *pdev); - /****************************************************************************/ static int _send_control_msg(struct pwc_device *pdev, @@ -113,10 +111,9 @@ static int _send_control_msg(struct pwc_device *pdev, void *kbuf = NULL; if (buflen) { - kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */ + kbuf = kmemdup(buf, buflen, GFP_KERNEL); /* not allowed on stack */ if (kbuf == NULL) return -ENOMEM; - memcpy(kbuf, buf, buflen); } rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), @@ -171,7 +168,8 @@ int send_control_msg(struct pwc_device *pdev, request, value, pdev->vcinterface, buf, buflen); } -static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) +static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames, + int *compression) { unsigned char buf[3]; int ret, fps; @@ -221,10 +219,10 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) /* Set various parameters */ pdev->vframes = frames; - pdev->vsize = size; pdev->valternate = pEntry->alternate; - pdev->image = pwc_image_sizes[size]; - pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; + pdev->width = pwc_image_sizes[size][0]; + pdev->height = pwc_image_sizes[size][1]; + pdev->frame_size = (pdev->width * pdev->height * 3) / 2; if (pEntry->compressed) { if (pdev->release < 5) { /* 4 fold compression */ pdev->vbandlength = 528; @@ -237,38 +235,40 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) } else pdev->vbandlength = 0; + + /* Let pwc-if.c:isoc_init know we don't support higher compression */ + *compression = 3; + return 0; } -static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, + int *compression) { unsigned char buf[13]; const struct Timon_table_entry *pChoose; int ret, fps; - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + if (size >= PSZ_MAX || frames < 5 || frames > 30 || + *compression < 0 || *compression > 3) return -EINVAL; if (size == PSZ_VGA && frames > 15) return -EINVAL; fps = (frames / 5) - 1; - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - */ + /* Find a supported framerate with progressively higher compression */ pChoose = NULL; - while (compression <= 3) { - pChoose = &Timon_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; + while (*compression <= 3) { + pChoose = &Timon_table[size][fps][*compression]; + if (pChoose->alternate != 0) + break; + (*compression)++; } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ memcpy(buf, pChoose->mode, 13); - if (snapshot) - buf[0] |= 0x80; ret = send_video_command(pdev, pdev->vendpoint, buf, 13); if (ret < 0) return ret; @@ -284,55 +284,38 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i /* Set various parameters */ pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; + pdev->width = pwc_image_sizes[size][0]; + pdev->height = pwc_image_sizes[size][1]; pdev->vbandlength = pChoose->bandlength; if (pChoose->bandlength > 0) - pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; + pdev->frame_size = (pChoose->bandlength * pdev->height) / 4; else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + pdev->frame_size = (pdev->width * pdev->height * 12) / 8; return 0; } -static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, + int *compression) { const struct Kiara_table_entry *pChoose = NULL; int fps, ret; unsigned char buf[12]; - struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; - if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + if (size >= PSZ_MAX || frames < 5 || frames > 30 || + *compression < 0 || *compression > 3) return -EINVAL; if (size == PSZ_VGA && frames > 15) return -EINVAL; fps = (frames / 5) - 1; - /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ - if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - /* Only available in case the raw palette is selected or - we have the decompressor available. This mode is - only available in compressed form - */ - PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n"); - pChoose = &RawEntry; - } - else - { - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - Skip this step when using RAW modes. - */ - snapshot = 0; - while (compression <= 3) { - pChoose = &Kiara_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; - } + /* Find a supported framerate with progressively higher compression */ + while (*compression <= 3) { + pChoose = &Kiara_table[size][fps][*compression]; + if (pChoose->alternate != 0) + break; + (*compression)++; } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ @@ -341,8 +324,6 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i /* usb_control_msg won't take staticly allocated arrays as argument?? */ memcpy(buf, pChoose->mode, 12); - if (snapshot) - buf[0] |= 0x80; /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12); @@ -359,61 +340,43 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i memcpy(pdev->cmd_buf, buf, 12); /* All set and go */ pdev->vframes = frames; - pdev->vsize = size; - pdev->vsnapshot = snapshot; pdev->valternate = pChoose->alternate; - pdev->image = pwc_image_sizes[size]; + pdev->width = pwc_image_sizes[size][0]; + pdev->height = pwc_image_sizes[size][1]; pdev->vbandlength = pChoose->bandlength; if (pdev->vbandlength > 0) - pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; + pdev->frame_size = (pdev->vbandlength * pdev->height) / 4; else - pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n", - pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength); + pdev->frame_size = (pdev->width * pdev->height * 12) / 8; + PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n", + pdev->frame_size, pdev->vframes, size, pdev->vbandlength); return 0; } - - -/** - @pdev: device structure - @width: viewport width - @height: viewport height - @frame: framerate, in fps - @compression: preferred compression ratio - @snapshot: snapshot mode or streaming - */ -int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) +int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, + int frames, int *compression) { int ret, size; PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt); - size = pwc_decode_size(pdev, width, height); - if (size < 0) { - PWC_DEBUG_MODULE("Could not find suitable size.\n"); - return -ERANGE; - } + size = pwc_get_size(pdev, width, height); PWC_TRACE("decode_size = %d.\n", size); if (DEVICE_USE_CODEC1(pdev->type)) { - ret = set_video_mode_Nala(pdev, size, frames); + ret = set_video_mode_Nala(pdev, size, frames, compression); } else if (DEVICE_USE_CODEC3(pdev->type)) { - ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); + ret = set_video_mode_Kiara(pdev, size, frames, compression); } else { - ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); + ret = set_video_mode_Timon(pdev, size, frames, compression); } if (ret < 0) { PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); return ret; } - pdev->view.x = width; - pdev->view.y = height; - pdev->vcompression = compression; pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; - pwc_set_image_buffer_size(pdev); - PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); + PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height); return 0; } @@ -470,34 +433,6 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i return ret; } -static void pwc_set_image_buffer_size(struct pwc_device *pdev) -{ - int factor = 0; - - /* for V4L2_PIX_FMT_YUV420 */ - switch (pdev->pixfmt) { - case V4L2_PIX_FMT_YUV420: - factor = 6; - break; - case V4L2_PIX_FMT_PWC1: - case V4L2_PIX_FMT_PWC2: - factor = 6; /* can be uncompressed YUV420P */ - break; - } - - /* Set sizes in bytes */ - pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; - pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; - - /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in - place), and y even (or you'll mixup U & V). This is less of a - problem for YUV420P. - */ - pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; - pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; -} - int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) { int ret; @@ -598,54 +533,6 @@ void pwc_camera_power(struct pwc_device *pdev, int power) power ? "on" : "off", r); } -static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) -{ - unsigned char buf; - - /* useful range is 0x01..0x20 */ - buf = speed / 0x7f0; - return send_control_msg(pdev, - SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_wb_speed(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf * 0x7f0; - return 0; -} - - -static int pwc_set_wb_delay(struct pwc_device *pdev, int delay) -{ - unsigned char buf; - - /* useful range is 0x01..0x3F */ - buf = (delay >> 10); - return send_control_msg(pdev, - SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); -} - -static int pwc_get_wb_delay(struct pwc_device *pdev, int *value) -{ - unsigned char buf; - int ret; - - ret = recv_control_msg(pdev, - GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *value = buf << 10; - return 0; -} - - int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) { unsigned char buf[2]; @@ -675,108 +562,6 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) return r; } -static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) -{ - unsigned char buf[2]; - int ret; - - if (pdev->type < 730) { - *on_value = -1; - *off_value = -1; - return 0; - } - - ret = recv_control_msg(pdev, - GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - *on_value = buf[0] * 100; - *off_value = buf[1] * 100; - return 0; -} - -static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - unsigned char buf; - - buf = flags & 0x03; // only lower two bits are currently used - return send_control_msg(pdev, - SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_mpt_reset(struct pwc_device *pdev, int flags) -{ - int ret; - ret = _pwc_mpt_reset(pdev, flags); - if (ret >= 0) { - pdev->pan_angle = 0; - pdev->tilt_angle = 0; - } - return ret; -} - -static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - unsigned char buf[4]; - - /* set new relative angle; angles are expressed in degrees * 100, - but cam as .5 degree resolution, hence divide by 200. Also - the angle must be multiplied by 64 before it's send to - the cam (??) - */ - pan = 64 * pan / 100; - tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ - buf[0] = pan & 0xFF; - buf[1] = (pan >> 8) & 0xFF; - buf[2] = tilt & 0xFF; - buf[3] = (tilt >> 8) & 0xFF; - return send_control_msg(pdev, - SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf)); -} - -int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) -{ - int ret; - - /* check absolute ranges */ - if (pan < pdev->angle_range.pan_min || - pan > pdev->angle_range.pan_max || - tilt < pdev->angle_range.tilt_min || - tilt > pdev->angle_range.tilt_max) - return -ERANGE; - - /* go to relative range, check again */ - pan -= pdev->pan_angle; - tilt -= pdev->tilt_angle; - /* angles are specified in degrees * 100, thus the limit = 36000 */ - if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000) - return -ERANGE; - - ret = _pwc_mpt_set_angle(pdev, pan, tilt); - if (ret >= 0) { - pdev->pan_angle += pan; - pdev->tilt_angle += tilt; - } - if (ret == -EPIPE) /* stall -> out of range */ - ret = -ERANGE; - return ret; -} - -static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) -{ - int ret; - unsigned char buf[5]; - - ret = recv_control_msg(pdev, - GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf)); - if (ret < 0) - return ret; - status->status = buf[0] & 0x7; // 3 bits are used for reporting - status->time_pan = (buf[1] << 8) + buf[2]; - status->time_tilt = (buf[3] << 8) + buf[4]; - return 0; -} - #ifdef CONFIG_USB_PWC_DEBUG int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) { @@ -801,420 +586,3 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) return 0; } #endif - - /* End of Add-Ons */ - /* ************************************************* */ - -/* Linux 2.5.something and 2.6 pass direct pointers to arguments of - ioctl() calls. With 2.4, you have to do tedious copy_from_user() - and copy_to_user() calls. With these macros we circumvent this, - and let me maintain only one source file. The functionality is - exactly the same otherwise. - */ - -/* define local variable for arg */ -#define ARG_DEF(ARG_type, ARG_name)\ - ARG_type *ARG_name = arg; -/* copy arg to local variable */ -#define ARG_IN(ARG_name) /* nothing */ -/* argument itself (referenced) */ -#define ARGR(ARG_name) (*ARG_name) -/* argument address */ -#define ARGA(ARG_name) ARG_name -/* copy local variable to arg */ -#define ARG_OUT(ARG_name) /* nothing */ - -/* - * Our ctrls use native values, but the old custom pwc ioctl interface expects - * values from 0 - 65535, define 2 helper functions to scale things. */ -static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl) -{ - return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum; -} - -static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val) -{ - return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535); -} - -long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) -{ - long ret = 0; - - switch(cmd) { - case VIDIOCPWCRUSER: - ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); - break; - - case VIDIOCPWCSUSER: - ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); - break; - - case VIDIOCPWCFACTORY: - ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); - break; - - case VIDIOCPWCSCQUAL: - { - ARG_DEF(int, qual) - - if (vb2_is_streaming(&pdev->vb_queue)) { - ret = -EBUSY; - break; - } - - ARG_IN(qual) - if (ARGR(qual) < 0 || ARGR(qual) > 3) - ret = -EINVAL; - else - ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); - break; - } - - case VIDIOCPWCGCQUAL: - { - ARG_DEF(int, qual) - - ARGR(qual) = pdev->vcompression; - ARG_OUT(qual) - break; - } - - case VIDIOCPWCPROBE: - { - ARG_DEF(struct pwc_probe, probe) - - strcpy(ARGR(probe).name, pdev->vdev.name); - ARGR(probe).type = pdev->type; - ARG_OUT(probe) - break; - } - - case VIDIOCPWCGSERIAL: - { - ARG_DEF(struct pwc_serial, serial) - - strcpy(ARGR(serial).serial, pdev->serial); - ARG_OUT(serial) - break; - } - - case VIDIOCPWCSAGC: - { - ARG_DEF(int, agc) - ARG_IN(agc) - ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0); - if (ret == 0 && ARGR(agc) >= 0) - ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc)); - break; - } - - case VIDIOCPWCGAGC: - { - ARG_DEF(int, agc) - if (v4l2_ctrl_g_ctrl(pdev->autogain)) - ARGR(agc) = -1; - else - ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain); - ARG_OUT(agc) - break; - } - - case VIDIOCPWCSSHUTTER: - { - ARG_DEF(int, shutter) - ARG_IN(shutter) - ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto, - /* Menu idx 0 = auto, idx 1 = manual */ - ARGR(shutter) >= 0); - if (ret == 0 && ARGR(shutter) >= 0) - ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter)); - break; - } - - case VIDIOCPWCSAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - ARG_IN(wb) - ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance, - ARGR(wb).mode); - if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) - ret = pwc_ioctl_s_ctrl(pdev->red_balance, - ARGR(wb).manual_red); - if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) - ret = pwc_ioctl_s_ctrl(pdev->blue_balance, - ARGR(wb).manual_blue); - break; - } - - case VIDIOCPWCGAWB: - { - ARG_DEF(struct pwc_whitebalance, wb) - ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance); - ARGR(wb).manual_red = ARGR(wb).read_red = - pwc_ioctl_g_ctrl(pdev->red_balance); - ARGR(wb).manual_blue = ARGR(wb).read_blue = - pwc_ioctl_g_ctrl(pdev->blue_balance); - ARG_OUT(wb) - break; - } - - case VIDIOCPWCSAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - if (ARGR(wbs).control_speed > 0) { - ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); - } - if (ARGR(wbs).control_delay > 0) { - ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); - } - break; - } - - case VIDIOCPWCGAWBSPEED: - { - ARG_DEF(struct pwc_wb_speed, wbs) - - ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); - if (ret < 0) - break; - ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); - if (ret < 0) - break; - ARG_OUT(wbs) - break; - } - - case VIDIOCPWCSLED: - { - ARG_DEF(struct pwc_leds, leds) - - ARG_IN(leds) - ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); - break; - } - - - case VIDIOCPWCGLED: - { - ARG_DEF(struct pwc_leds, leds) - - ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); - ARG_OUT(leds) - break; - } - - case VIDIOCPWCSCONTOUR: - { - ARG_DEF(int, contour) - ARG_IN(contour) - ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0); - if (ret == 0 && ARGR(contour) >= 0) - ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour)); - break; - } - - case VIDIOCPWCGCONTOUR: - { - ARG_DEF(int, contour) - if (v4l2_ctrl_g_ctrl(pdev->autocontour)) - ARGR(contour) = -1; - else - ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour); - ARG_OUT(contour) - break; - } - - case VIDIOCPWCSBACKLIGHT: - { - ARG_DEF(int, backlight) - ARG_IN(backlight) - ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight)); - break; - } - - case VIDIOCPWCGBACKLIGHT: - { - ARG_DEF(int, backlight) - ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight); - ARG_OUT(backlight) - break; - } - - case VIDIOCPWCSFLICKER: - { - ARG_DEF(int, flicker) - ARG_IN(flicker) - ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker)); - break; - } - - case VIDIOCPWCGFLICKER: - { - ARG_DEF(int, flicker) - ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker); - ARG_OUT(flicker) - break; - } - - case VIDIOCPWCSDYNNOISE: - { - ARG_DEF(int, dynnoise) - ARG_IN(dynnoise) - ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise)); - break; - } - - case VIDIOCPWCGDYNNOISE: - { - ARG_DEF(int, dynnoise) - ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction); - ARG_OUT(dynnoise); - break; - } - - case VIDIOCPWCGREALSIZE: - { - ARG_DEF(struct pwc_imagesize, size) - - ARGR(size).width = pdev->image.x; - ARGR(size).height = pdev->image.y; - ARG_OUT(size) - break; - } - - case VIDIOCPWCMPTRESET: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(int, flags) - - ARG_IN(flags) - ret = pwc_mpt_reset(pdev, ARGR(flags)); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGRANGE: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_range, range) - - ARGR(range) = pdev->angle_range; - ARG_OUT(range) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSANGLE: - { - int new_pan, new_tilt; - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARG_IN(angles) - /* The camera can only set relative angles, so - do some calculations when getting an absolute angle . - */ - if (ARGR(angles).absolute) - { - new_pan = ARGR(angles).pan; - new_tilt = ARGR(angles).tilt; - } - else - { - new_pan = pdev->pan_angle + ARGR(angles).pan; - new_tilt = pdev->tilt_angle + ARGR(angles).tilt; - } - ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTGANGLE: - { - - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_angles, angles) - - ARGR(angles).absolute = 1; - ARGR(angles).pan = pdev->pan_angle; - ARGR(angles).tilt = pdev->tilt_angle; - ARG_OUT(angles) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCMPTSTATUS: - { - if (pdev->features & FEATURE_MOTOR_PANTILT) - { - ARG_DEF(struct pwc_mpt_status, status) - - ret = pwc_mpt_get_status(pdev, ARGA(status)); - ARG_OUT(status) - } - else - { - ret = -ENXIO; - } - break; - } - - case VIDIOCPWCGVIDCMD: - { - ARG_DEF(struct pwc_video_command, vcmd); - - ARGR(vcmd).type = pdev->type; - ARGR(vcmd).release = pdev->release; - ARGR(vcmd).command_len = pdev->cmd_len; - memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(vcmd).bandlength = pdev->vbandlength; - ARGR(vcmd).frame_size = pdev->frame_size; - ARG_OUT(vcmd) - break; - } - /* - case VIDIOCPWCGVIDTABLE: - { - ARG_DEF(struct pwc_table_init_buffer, table); - ARGR(table).len = pdev->cmd_len; - memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); - ARG_OUT(table) - break; - } - */ - - default: - ret = -ENOIOCTLCMD; - break; - } - - if (ret > 0) - return 0; - return ret; -} - - -/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c index 06a4e877ba40..2c6709112b2f 100644 --- a/drivers/media/video/pwc/pwc-dec23.c +++ b/drivers/media/video/pwc/pwc-dec23.c @@ -27,7 +27,6 @@ #include "pwc-timon.h" #include "pwc-kiara.h" #include "pwc-dec23.h" -#include <media/pwc-ioctl.h> #include <linux/string.h> #include <linux/slab.h> @@ -51,13 +50,6 @@ # define USE_LOOKUP_TABLE_TO_CLAMP 1 #endif -/* - * ENABLE_BAYER_DECODER - * 0: bayer decoder is not build (save some space) - * 1: bayer decoder is build and can be used - */ -#define ENABLE_BAYER_DECODER 0 - static void build_subblock_pattern(struct pwc_dec23_private *pdec) { static const unsigned int initial_values[12] = { @@ -315,6 +307,8 @@ int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd) } pdec = pwc->decompress_data; + mutex_init(&pdec->lock); + if (DEVICE_USE_CODEC3(type)) { flags = cmd[2] & 0x18; if (flags == 8) @@ -467,123 +461,6 @@ static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned i #endif } -#if ENABLE_BAYER_DECODER -/* - * Format: 8x2 pixels - * . G . G . G . G . G . G . G - * . . . . . . . . . . . . . . - * . G . G . G . G . G . G . G - * . . . . . . . . . . . . . . - * or - * . . . . . . . . . . . . . . - * G . G . G . G . G . G . G . - * . . . . . . . . . . . . . . - * G . G . G . G . G . G . G . -*/ -static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - unsigned char *d = dst; - const int *c = src; - - d[0] = cm[c[0] >> scalebits]; - d[2] = cm[c[1] >> scalebits]; - d[4] = cm[c[2] >> scalebits]; - d[6] = cm[c[3] >> scalebits]; - d[8] = cm[c[4] >> scalebits]; - d[10] = cm[c[5] >> scalebits]; - d[12] = cm[c[6] >> scalebits]; - d[14] = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line; - d[0] = cm[c[8] >> scalebits]; - d[2] = cm[c[9] >> scalebits]; - d[4] = cm[c[10] >> scalebits]; - d[6] = cm[c[11] >> scalebits]; - d[8] = cm[c[12] >> scalebits]; - d[10] = cm[c[13] >> scalebits]; - d[12] = cm[c[14] >> scalebits]; - d[14] = cm[c[15] >> scalebits]; -#else - int i; - unsigned char *d; - const int *c = src; - - d = dst; - for (i = 0; i < 8; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 8; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); -#endif -} -#endif - -#if ENABLE_BAYER_DECODER -/* - * Format: 4x4 pixels - * R . R . R . R - * . B . B . B . - * R . R . R . R - * . B . B . B . - */ -static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits) -{ -#if UNROLL_LOOP_FOR_COPY - /* Unroll all loops */ - const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE; - unsigned char *d = dst; - const int *c = src; - - d[0] = cm[c[0] >> scalebits]; - d[2] = cm[c[1] >> scalebits]; - d[4] = cm[c[2] >> scalebits]; - d[6] = cm[c[3] >> scalebits]; - - d = dst + bytes_per_line; - d[1] = cm[c[4] >> scalebits]; - d[3] = cm[c[5] >> scalebits]; - d[5] = cm[c[6] >> scalebits]; - d[7] = cm[c[7] >> scalebits]; - - d = dst + bytes_per_line*2; - d[0] = cm[c[8] >> scalebits]; - d[2] = cm[c[9] >> scalebits]; - d[4] = cm[c[10] >> scalebits]; - d[6] = cm[c[11] >> scalebits]; - - d = dst + bytes_per_line*3; - d[1] = cm[c[12] >> scalebits]; - d[3] = cm[c[13] >> scalebits]; - d[5] = cm[c[14] >> scalebits]; - d[7] = cm[c[15] >> scalebits]; -#else - int i; - unsigned char *d; - const int *c = src; - - d = dst; - for (i = 0; i < 4; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line; - for (i = 0; i < 4; i++, c++) - d[i*2+1] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*2; - for (i = 0; i < 4; i++, c++) - d[i*2] = CLAMP((*c) >> scalebits); - - d = dst + bytes_per_line*3; - for (i = 0; i < 4; i++, c++) - d[i*2+1] = CLAMP((*c) >> scalebits); -#endif -} -#endif - /* * To manage the stream, we keep bits in a 32 bits register. * fill_nbits(n): fill the reservoir with at least n bits @@ -775,146 +652,45 @@ static void DecompressBand23(struct pwc_dec23_private *pdec, } -#if ENABLE_BAYER_DECODER -/* - * Size need to be a multiple of 8 in width - * - * Return a block of four line encoded like this: - * - * G R G R G R G R G R G R G R G R - * B G B G B G B G B G B G B G B G - * G R G R G R G R G R G R G R G R - * B G B G B G B G B G B G B G B G - * - */ -static void DecompressBandBayer(struct pwc_dec23_private *pdec, - const unsigned char *rawyuv, - unsigned char *rgbbayer, - unsigned int compressed_image_width, - unsigned int real_image_width) -{ - int compression_index, nblocks; - const unsigned char *ptable0004; - const unsigned char *ptable8004; - unsigned char *dest; - - pdec->reservoir = 0; - pdec->nbits_in_reservoir = 0; - pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */ - - get_nbits(pdec, 4, compression_index); - - /* pass 1: uncompress RB component */ - nblocks = compressed_image_width / 4; - - ptable0004 = pdec->table_0004_pass1[compression_index]; - ptable8004 = pdec->table_8004_pass1[compression_index]; - dest = rgbbayer; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits); - dest += 8; - nblocks--; - } - - /* pass 2: uncompress G component */ - nblocks = compressed_image_width / 8; - - ptable0004 = pdec->table_0004_pass2[compression_index]; - ptable8004 = pdec->table_8004_pass2[compression_index]; - - /* Each block decode a square of 4x4 */ - while (nblocks) { - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits); - - decode_block(pdec, ptable0004, ptable8004); - copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits); - - rgbbayer += 16; - nblocks -= 2; - } -} -#endif - - /** * * Uncompress a pwc23 buffer. * - * pwc.view: size of the image wanted - * pwc.image: size of the image returned by the camera - * pwc.offset: (x,y) to displayer image in the view - * * src: raw data * dst: image output - * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER */ void pwc_dec23_decompress(const struct pwc_device *pwc, const void *src, - void *dst, - int flags) + void *dst) { - int bandlines_left, stride, bytes_per_block; - - bandlines_left = pwc->image.y / 4; - bytes_per_block = pwc->view.x * 4; - - if (flags & PWCX_FLAG_BAYER) { -#if ENABLE_BAYER_DECODER - /* RGB Bayer format */ - unsigned char *rgbout; - - stride = pwc->view.x * pwc->offset.y; - rgbout = dst + stride + pwc->offset.x; - - - while (bandlines_left--) { - - DecompressBandBayer(pwc->decompress_data, - src, - rgbout, - pwc->image.x, pwc->view.x); - - src += pwc->vbandlength; - rgbout += bytes_per_block; - - } -#else - memset(dst, 0, pwc->view.x * pwc->view.y); -#endif - - } else { - /* YUV420P image format */ - unsigned char *pout_planar_y; - unsigned char *pout_planar_u; - unsigned char *pout_planar_v; - unsigned int plane_size; - - plane_size = pwc->view.x * pwc->view.y; - - /* offset in Y plane */ - stride = pwc->view.x * pwc->offset.y; - pout_planar_y = dst + stride + pwc->offset.x; - - /* offsets in U/V planes */ - stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2; - pout_planar_u = dst + plane_size + stride; - pout_planar_v = dst + plane_size + plane_size / 4 + stride; - - while (bandlines_left--) { - - DecompressBand23(pwc->decompress_data, - src, - pout_planar_y, pout_planar_u, pout_planar_v, - pwc->image.x, pwc->view.x); - src += pwc->vbandlength; - pout_planar_y += bytes_per_block; - pout_planar_u += pwc->view.x; - pout_planar_v += pwc->view.x; - - } + int bandlines_left, bytes_per_block; + struct pwc_dec23_private *pdec = pwc->decompress_data; + + /* YUV420P image format */ + unsigned char *pout_planar_y; + unsigned char *pout_planar_u; + unsigned char *pout_planar_v; + unsigned int plane_size; + + mutex_lock(&pdec->lock); + + bandlines_left = pwc->height / 4; + bytes_per_block = pwc->width * 4; + plane_size = pwc->height * pwc->width; + + pout_planar_y = dst; + pout_planar_u = dst + plane_size; + pout_planar_v = dst + plane_size + plane_size / 4; + + while (bandlines_left--) { + DecompressBand23(pwc->decompress_data, + src, + pout_planar_y, pout_planar_u, pout_planar_v, + pwc->width, pwc->width); + src += pwc->vbandlength; + pout_planar_y += bytes_per_block; + pout_planar_u += pwc->width; + pout_planar_v += pwc->width; } + mutex_unlock(&pdec->lock); } diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h index a0ac4f3dff81..d64a3c281af6 100644 --- a/drivers/media/video/pwc/pwc-dec23.h +++ b/drivers/media/video/pwc/pwc-dec23.h @@ -29,6 +29,8 @@ struct pwc_dec23_private { + struct mutex lock; + unsigned int scalebits; unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */ @@ -52,6 +54,5 @@ struct pwc_dec23_private int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd); void pwc_dec23_decompress(const struct pwc_device *pwc, const void *src, - void *dst, - int flags); + void *dst); #endif diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 01ff643e682d..943d37ad0d33 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -134,7 +134,6 @@ static int default_fps = 10; #endif static int power_save = -1; static int led_on = 100, led_off; /* defaults to LED that is on while in use */ -static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */ static struct { int type; char serial_number[30]; @@ -144,17 +143,15 @@ static struct { /***/ -static int pwc_video_open(struct file *file); static int pwc_video_close(struct file *file); static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); -static void pwc_video_release(struct video_device *vfd); static const struct v4l2_file_operations pwc_fops = { .owner = THIS_MODULE, - .open = pwc_video_open, + .open = v4l2_fh_open, .release = pwc_video_close, .read = pwc_video_read, .poll = pwc_video_poll, @@ -163,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = { }; static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ - .release = pwc_video_release, + .release = video_device_release_empty, .fops = &pwc_fops, .ioctl_ops = &pwc_ioctl_ops, }; @@ -191,7 +188,6 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down) { if (down) { PWC_TRACE("Snapshot button pressed.\n"); - pdev->snapshot_button_status = 1; } else { PWC_TRACE("Snapshot button released.\n"); } @@ -375,6 +371,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) int i, j, ret; struct usb_interface *intf; struct usb_host_interface *idesc = NULL; + int compression = 0; /* 0..3 = uncompressed..high */ if (pdev->iso_init) return 0; @@ -386,6 +383,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) pdev->visoc_errors = 0; udev = pdev->udev; +retry: + /* We first try with low compression and then retry with a higher + compression setting if there is not enough bandwidth. */ + ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, + pdev->vframes, &compression); + /* Get the current alternate interface, adjust packet size */ intf = usb_ifnum_to_if(udev, 0); if (intf) @@ -408,9 +411,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) } /* Set alternate interface */ - ret = 0; PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate); ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (ret == -ENOSPC && compression < 3) { + compression++; + goto retry; + } if (ret < 0) return ret; @@ -454,6 +460,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) /* link */ for (i = 0; i < MAX_ISO_BUFS; i++) { ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL); + if (ret == -ENOSPC && compression < 3) { + compression++; + pdev->iso_init = 1; + pwc_isoc_cleanup(pdev); + goto retry; + } if (ret) { PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); pdev->iso_init = 1; @@ -517,12 +529,11 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); } -/* - * Release all queued buffers, no need to take queued_bufs_lock, since all - * iso urbs have been killed when we're called so pwc_isoc_handler won't run. - */ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) { + unsigned long flags = 0; + + spin_lock_irqsave(&pdev->queued_bufs_lock, flags); while (!list_empty(&pdev->queued_bufs)) { struct pwc_frame_buf *buf; @@ -531,84 +542,7 @@ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } -} - -/********* - * sysfs - *********/ -static struct pwc_device *cd_to_pwc(struct device *cd) -{ - struct video_device *vdev = to_video_device(cd); - return video_get_drvdata(vdev); -} - -static ssize_t show_pan_tilt(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); -} - -static ssize_t store_pan_tilt(struct device *class_dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int pan, tilt; - int ret = -EINVAL; - - if (strncmp(buf, "reset", 5) == 0) - ret = pwc_mpt_reset(pdev, 0x3); - - else if (sscanf(buf, "%d %d", &pan, &tilt) > 0) - ret = pwc_mpt_set_angle(pdev, pan, tilt); - - if (ret < 0) - return ret; - return strlen(buf); -} -static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); - -static ssize_t show_snapshot_button_status(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int status = pdev->snapshot_button_status; - pdev->snapshot_button_status = 0; - return sprintf(buf, "%d\n", status); -} - -static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); - -static int pwc_create_sysfs_files(struct pwc_device *pdev) -{ - int rc; - - rc = device_create_file(&pdev->vdev.dev, &dev_attr_button); - if (rc) - goto err; - if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = device_create_file(&pdev->vdev.dev, &dev_attr_pan_tilt); - if (rc) - goto err_button; - } - - return 0; - -err_button: - device_remove_file(&pdev->vdev.dev, &dev_attr_button); -err: - PWC_ERROR("Could not create sysfs files.\n"); - return rc; -} - -static void pwc_remove_sysfs_files(struct pwc_device *pdev) -{ - if (pdev->features & FEATURE_MOTOR_PANTILT) - device_remove_file(&pdev->vdev.dev, &dev_attr_pan_tilt); - device_remove_file(&pdev->vdev.dev, &dev_attr_button); + spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); } #ifdef CONFIG_USB_PWC_DEBUG @@ -644,25 +578,25 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type) /***************************************************************************/ /* Video4Linux functions */ -static int pwc_video_open(struct file *file) +int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file) { - struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - - PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); + int r = 0; - pdev = video_get_drvdata(vdev); - if (!pdev->udev) - return -ENODEV; - - file->private_data = vdev; - PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); - return 0; + mutex_lock(&pdev->capt_file_lock); + if (pdev->capt_file != NULL && + pdev->capt_file != file) { + r = -EBUSY; + goto leave; + } + pdev->capt_file = file; +leave: + mutex_unlock(&pdev->capt_file_lock); + return r; } -static void pwc_video_release(struct video_device *vfd) +static void pwc_video_release(struct v4l2_device *v) { - struct pwc_device *pdev = container_of(vfd, struct pwc_device, vdev); + struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); int hint; /* search device_hint[] table if we occupy a slot, by any chance */ @@ -685,44 +619,33 @@ static void pwc_video_release(struct video_device *vfd) static int pwc_video_close(struct file *file) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - - PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); + struct pwc_device *pdev = video_drvdata(file); - pdev = video_get_drvdata(vdev); if (pdev->capt_file == file) { vb2_queue_release(&pdev->vb_queue); pdev->capt_file = NULL; } - - PWC_DEBUG_OPEN("<< video_close()\n"); - return 0; + return v4l2_fh_release(file); } static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev = video_get_drvdata(vdev); + struct pwc_device *pdev = video_drvdata(file); if (!pdev->udev) return -ENODEV; - if (pdev->capt_file != NULL && - pdev->capt_file != file) + if (pwc_test_n_set_capt_file(pdev, file)) return -EBUSY; - pdev->capt_file = file; - return vb2_read(&pdev->vb_queue, buf, count, ppos, file->f_flags & O_NONBLOCK); } static unsigned int pwc_video_poll(struct file *file, poll_table *wait) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev = video_get_drvdata(vdev); + struct pwc_device *pdev = video_drvdata(file); if (!pdev->udev) return POLL_ERR; @@ -732,8 +655,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *vdev = file->private_data; - struct pwc_device *pdev = video_get_drvdata(vdev); + struct pwc_device *pdev = video_drvdata(file); if (pdev->capt_file != file) return -EBUSY; @@ -749,6 +671,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int sizes[], void *alloc_ctxs[]) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + int size; if (*nbuffers < MIN_FRAMES) *nbuffers = MIN_FRAMES; @@ -757,7 +680,9 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, *nplanes = 1; - sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); + size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT); + sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] * + pwc_image_sizes[size][1] * 3 / 2); return 0; } @@ -812,56 +737,59 @@ static void buffer_queue(struct vb2_buffer *vb) unsigned long flags = 0; spin_lock_irqsave(&pdev->queued_bufs_lock, flags); - list_add_tail(&buf->list, &pdev->queued_bufs); + /* Check the device has not disconnected between prep and queuing */ + if (pdev->udev) + list_add_tail(&buf->list, &pdev->queued_bufs); + else + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); } static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + int r; - if (!pdev->udev) - return -ENODEV; + mutex_lock(&pdev->udevlock); + if (!pdev->udev) { + r = -ENODEV; + goto leave; + } /* Turn on camera and set LEDS on */ pwc_camera_power(pdev, 1); - if (pdev->power_save) { - /* Restore video mode */ - pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, - pdev->vframes, pdev->vcompression, - pdev->vsnapshot); - } pwc_set_leds(pdev, led_on, led_off); - return pwc_isoc_init(pdev); + r = pwc_isoc_init(pdev); + if (r) { + /* If we failed turn camera and LEDS back off */ + pwc_set_leds(pdev, 0, 0); + pwc_camera_power(pdev, 0); + /* And cleanup any queued bufs!! */ + pwc_cleanup_queued_bufs(pdev); + } +leave: + mutex_unlock(&pdev->udevlock); + return r; } static int stop_streaming(struct vb2_queue *vq) { struct pwc_device *pdev = vb2_get_drv_priv(vq); + mutex_lock(&pdev->udevlock); if (pdev->udev) { pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); pwc_isoc_cleanup(pdev); } + mutex_unlock(&pdev->udevlock); + pwc_cleanup_queued_bufs(pdev); return 0; } -static void pwc_lock(struct vb2_queue *vq) -{ - struct pwc_device *pdev = vb2_get_drv_priv(vq); - mutex_lock(&pdev->modlock); -} - -static void pwc_unlock(struct vb2_queue *vq) -{ - struct pwc_device *pdev = vb2_get_drv_priv(vq); - mutex_unlock(&pdev->modlock); -} - static struct vb2_ops pwc_vb_queue_ops = { .queue_setup = queue_setup, .buf_init = buffer_init, @@ -871,8 +799,6 @@ static struct vb2_ops pwc_vb_queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = pwc_unlock, - .wait_finish = pwc_lock, }; /***************************************************************************/ @@ -889,6 +815,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id int vendor_id, product_id, type_id; int hint, rc; int features = 0; + int compression = 0; int video_nr = -1; /* default: use next available device */ int my_power_save = power_save; char serial_number[30], *name; @@ -1150,27 +1077,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id } pdev->type = type_id; pdev->vframes = default_fps; - strcpy(pdev->serial, serial_number); pdev->features = features; - if (vendor_id == 0x046D && product_id == 0x08B5) { - /* Logitech QuickCam Orbit - The ranges have been determined experimentally; they may differ from cam to cam. - Also, the exact ranges left-right and up-down are different for my cam - */ - pdev->angle_range.pan_min = -7000; - pdev->angle_range.pan_max = 7000; - pdev->angle_range.tilt_min = -3000; - pdev->angle_range.tilt_max = 2500; - } pwc_construct(pdev); /* set min/max sizes correct */ - mutex_init(&pdev->modlock); + mutex_init(&pdev->capt_file_lock); mutex_init(&pdev->udevlock); spin_lock_init(&pdev->queued_bufs_lock); INIT_LIST_HEAD(&pdev->queued_bufs); pdev->udev = udev; - pdev->vcompression = pwc_preferred_compression; pdev->power_save = my_power_save; /* Init videobuf2 queue structure */ @@ -1185,9 +1100,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id /* Init video_device structure */ memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev.parent = &intf->dev; - pdev->vdev.lock = &pdev->modlock; strcpy(pdev->vdev.name, name); + set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags); video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); @@ -1211,9 +1125,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = pdev; - PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); - usb_set_intfdata(intf, pdev); - #ifdef CONFIG_USB_PWC_DEBUG /* Query sensor type */ if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { @@ -1227,8 +1138,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pwc_set_leds(pdev, 0, 0); /* Setup intial videomode */ - rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y, - pdev->vframes, pdev->vcompression, 0); + rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT, pdev->vframes, + &compression); if (rc) goto err_free_mem; @@ -1239,20 +1150,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id goto err_free_mem; } - pdev->vdev.ctrl_handler = &pdev->ctrl_handler; - /* And powerdown the camera until streaming starts */ pwc_camera_power(pdev, 0); + /* Register the v4l2_device structure */ + pdev->v4l2_dev.release = pwc_video_release; + rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev); + if (rc) { + PWC_ERROR("Failed to register v4l2-device (%d).\n", rc); + goto err_free_controls; + } + + pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; + pdev->vdev.v4l2_dev = &pdev->v4l2_dev; + rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (rc < 0) { PWC_ERROR("Failed to register as video device (%d).\n", rc); - goto err_free_controls; + goto err_unregister_v4l2_dev; } - rc = pwc_create_sysfs_files(pdev); - if (rc) - goto err_video_unreg; - PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev)); #ifdef CONFIG_USB_PWC_INPUT_EVDEV @@ -1261,7 +1177,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (!pdev->button_dev) { PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); rc = -ENOMEM; - pwc_remove_sysfs_files(pdev); goto err_video_unreg; } @@ -1279,7 +1194,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (rc) { input_free_device(pdev->button_dev); pdev->button_dev = NULL; - pwc_remove_sysfs_files(pdev); goto err_video_unreg; } #endif @@ -1287,13 +1201,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return 0; err_video_unreg: - if (hint < MAX_DEV_HINTS) - device_hint[hint].pdev = NULL; video_unregister_device(&pdev->vdev); +err_unregister_v4l2_dev: + v4l2_device_unregister(&pdev->v4l2_dev); err_free_controls: v4l2_ctrl_handler_free(&pdev->ctrl_handler); err_free_mem: - usb_set_intfdata(intf, NULL); + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = NULL; kfree(pdev); return rc; } @@ -1301,27 +1216,26 @@ err_free_mem: /* The user yanked out the cable... */ static void usb_pwc_disconnect(struct usb_interface *intf) { - struct pwc_device *pdev = usb_get_intfdata(intf); + struct v4l2_device *v = usb_get_intfdata(intf); + struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev); mutex_lock(&pdev->udevlock); - mutex_lock(&pdev->modlock); - - usb_set_intfdata(intf, NULL); /* No need to keep the urbs around after disconnection */ pwc_isoc_cleanup(pdev); - pwc_cleanup_queued_bufs(pdev); pdev->udev = NULL; - - mutex_unlock(&pdev->modlock); mutex_unlock(&pdev->udevlock); - pwc_remove_sysfs_files(pdev); + pwc_cleanup_queued_bufs(pdev); + video_unregister_device(&pdev->vdev); + v4l2_device_unregister(&pdev->v4l2_dev); #ifdef CONFIG_USB_PWC_INPUT_EVDEV if (pdev->button_dev) input_unregister_device(pdev->button_dev); #endif + + v4l2_device_put(&pdev->v4l2_dev); } @@ -1330,7 +1244,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf) */ static int fps; -static int compression = -1; static int leds[2] = { -1, -1 }; static unsigned int leds_nargs; static char *dev_hint[MAX_DEV_HINTS]; @@ -1341,7 +1254,6 @@ module_param(fps, int, 0444); module_param_named(trace, pwc_trace, int, 0644); #endif module_param(power_save, int, 0644); -module_param(compression, int, 0444); module_param_array(leds, int, &leds_nargs, 0444); module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); @@ -1350,7 +1262,6 @@ MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful rang MODULE_PARM_DESC(trace, "For debugging purposes"); #endif MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); -MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); MODULE_PARM_DESC(dev_hint, "Device node hints"); @@ -1384,14 +1295,6 @@ static int __init usb_pwc_init(void) PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); } - if (compression >= 0) { - if (compression > 3) { - PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); - return -EINVAL; - } - pwc_preferred_compression = compression; - PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression); - } if (leds[0] >= 0) led_on = leds[0]; if (leds[1] >= 0) diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h index 047dad8c15f7..8e02b7ac2139 100644 --- a/drivers/media/video/pwc/pwc-kiara.h +++ b/drivers/media/video/pwc/pwc-kiara.h @@ -27,7 +27,7 @@ #ifndef PWC_KIARA_H #define PWC_KIARA_H -#include <media/pwc-ioctl.h> +#include "pwc.h" #define PWC_FPS_MAX_KIARA 6 diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c index 0b031336eab8..23a55b5814fc 100644 --- a/drivers/media/video/pwc/pwc-misc.c +++ b/drivers/media/video/pwc/pwc-misc.c @@ -27,67 +27,47 @@ #include "pwc.h" -const struct pwc_coord pwc_image_sizes[PSZ_MAX] = +const int pwc_image_sizes[PSZ_MAX][2] = { - { 128, 96, 0 }, /* sqcif */ - { 160, 120, 0 }, /* qsif */ - { 176, 144, 0 }, /* qcif */ - { 320, 240, 0 }, /* sif */ - { 352, 288, 0 }, /* cif */ - { 640, 480, 0 }, /* vga */ + { 128, 96 }, /* sqcif */ + { 160, 120 }, /* qsif */ + { 176, 144 }, /* qcif */ + { 320, 240 }, /* sif */ + { 352, 288 }, /* cif */ + { 640, 480 }, /* vga */ }; /* x,y -> PSZ_ */ -int pwc_decode_size(struct pwc_device *pdev, int width, int height) +int pwc_get_size(struct pwc_device *pdev, int width, int height) { - int i, find; - - /* Make sure we don't go beyond our max size. - NB: we have different limits for RAW and normal modes. In case - you don't have the decompressor loaded or use RAW mode, - the maximum viewable size is smaller. - */ - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - { - if (width > pdev->abs_max.x || height > pdev->abs_max.y) - { - PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); - return -1; - } - } - else - { - if (width > pdev->view_max.x || height > pdev->view_max.y) - { - PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n"); - return -1; - } - } + int i; /* Find the largest size supported by the camera that fits into the - requested size. - */ - find = -1; + requested size. */ + for (i = PSZ_MAX - 1; i >= 0; i--) { + if (!(pdev->image_mask & (1 << i))) + continue; + + if (pwc_image_sizes[i][0] <= width && + pwc_image_sizes[i][1] <= height) + return i; + } + + /* No mode found, return the smallest mode we have */ for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1 << i)) { - if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) - find = i; - } + if (pdev->image_mask & (1 << i)) + return i; } - return find; + + /* Never reached there always is atleast one supported mode */ + return 0; } -/* initialize variables depending on type and decompressor*/ +/* initialize variables depending on type and decompressor */ void pwc_construct(struct pwc_device *pdev) { if (DEVICE_USE_CODEC1(pdev->type)) { - pdev->view_min.x = 128; - pdev->view_min.y = 96; - pdev->view_max.x = 352; - pdev->view_max.y = 288; - pdev->abs_max.x = 352; - pdev->abs_max.y = 288; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; pdev->vcinterface = 2; pdev->vendpoint = 4; @@ -96,13 +76,7 @@ void pwc_construct(struct pwc_device *pdev) } else if (DEVICE_USE_CODEC3(pdev->type)) { - pdev->view_min.x = 160; - pdev->view_min.y = 120; - pdev->view_max.x = 640; - pdev->view_max.y = 480; pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 5; pdev->frame_header_size = TOUCAM_HEADER_SIZE; @@ -110,20 +84,11 @@ void pwc_construct(struct pwc_device *pdev) } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ { - pdev->view_min.x = 128; - pdev->view_min.y = 96; - /* Anthill bug #38: PWC always reports max size, even without PWCX */ - pdev->view_max.x = 640; - pdev->view_max.y = 480; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; - pdev->abs_max.x = 640; - pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 4; pdev->frame_header_size = 0; pdev->frame_trailer_size = 0; } pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ - pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; - pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; } diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h index a6e22224c95f..270c5b9010f6 100644 --- a/drivers/media/video/pwc/pwc-timon.h +++ b/drivers/media/video/pwc/pwc-timon.h @@ -42,7 +42,7 @@ #ifndef PWC_TIMON_H #define PWC_TIMON_H -#include <media/pwc-ioctl.h> +#include "pwc.h" #define PWC_FPS_MAX_TIMON 6 diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c index 51265092bd31..b65903fbcf0d 100644 --- a/drivers/media/video/pwc/pwc-uncompress.c +++ b/drivers/media/video/pwc/pwc-uncompress.c @@ -35,7 +35,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) { - int n, line, col, stride; + int n, line, col; void *yuv, *image; u16 *src; u16 *dsty, *dstu, *dstv; @@ -60,35 +60,23 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) return 0; } - vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size); + vb2_set_plane_payload(&fbuf->vb, 0, + pdev->width * pdev->height * 3 / 2); if (pdev->vbandlength == 0) { /* Uncompressed mode. - * We copy the data into the output buffer, using the viewport - * size (which may be larger than the image size). - * Unfortunately we have to do a bit of byte stuffing to get - * the desired output format/size. * * We do some byte shuffling here to go from the * native format to YUV420P. */ src = (u16 *)yuv; - n = pdev->view.x * pdev->view.y; + n = pdev->width * pdev->height; + dsty = (u16 *)(image); + dstu = (u16 *)(image + n); + dstv = (u16 *)(image + n + n / 4); - /* offset in Y plane */ - stride = pdev->view.x * pdev->offset.y + pdev->offset.x; - dsty = (u16 *)(image + stride); - - /* offsets in U/V planes */ - stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; - dstu = (u16 *)(image + n + stride); - dstv = (u16 *)(image + n + n / 4 + stride); - - /* increment after each line */ - stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ - - for (line = 0; line < pdev->image.y; line++) { - for (col = 0; col < pdev->image.x; col += 4) { + for (line = 0; line < pdev->height; line++) { + for (col = 0; col < pdev->width; col += 4) { *dsty++ = *src++; *dsty++ = *src++; if (line & 1) @@ -96,11 +84,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) else *dstu++ = *src++; } - dsty += stride; - if (line & 1) - dstv += (stride >> 1); - else - dstu += (stride >> 1); } return 0; @@ -111,12 +94,6 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) * the decompressor routines will write the data in planar format * immediately. */ - if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) { - PWC_ERROR("Mode Bayer is not supported for now\n"); - /* flags |= PWCX_FLAG_BAYER; */ - return -ENXIO; /* No such device or address: missing decompressor */ - } - if (DEVICE_USE_CODEC1(pdev->type)) { /* TODO & FIXME */ @@ -124,10 +101,7 @@ int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) return -ENXIO; /* No such device or address: missing decompressor */ } else { - pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR); + pwc_dec23_decompress(pdev, yuv, image); } return 0; } - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index a10ff6b64acf..80e25842e84a 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -49,6 +49,7 @@ static const struct v4l2_ctrl_ops pwc_ctrl_ops = { enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto }; enum { custom_autocontour, custom_contour, custom_noise_reduction, + custom_awb_speed, custom_awb_delay, custom_save_user, custom_restore_user, custom_restore_factory }; const char * const pwc_auto_whitebal_qmenu[] = { @@ -138,6 +139,26 @@ static const struct v4l2_ctrl_config pwc_restore_factory_cfg = { .name = "Restore Factory Settings", }; +static const struct v4l2_ctrl_config pwc_awb_speed_cfg = { + .ops = &pwc_ctrl_ops, + .id = PWC_CID_CUSTOM(awb_speed), + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Auto White Balance Speed", + .min = 1, + .max = 32, + .step = 1, +}; + +static const struct v4l2_ctrl_config pwc_awb_delay_cfg = { + .ops = &pwc_ctrl_ops, + .id = PWC_CID_CUSTOM(awb_delay), + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Auto White Balance Delay", + .min = 0, + .max = 63, + .step = 1, +}; + int pwc_init_controls(struct pwc_device *pdev) { struct v4l2_ctrl_handler *hdl; @@ -338,6 +359,23 @@ int pwc_init_controls(struct pwc_device *pdev) if (pdev->restore_factory) pdev->restore_factory->flags |= V4L2_CTRL_FLAG_UPDATE; + /* Auto White Balance speed & delay */ + r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, + AWB_CONTROL_SPEED_FORMATTER, &def); + if (r || def < 1 || def > 32) + def = 1; + cfg = pwc_awb_speed_cfg; + cfg.def = def; + pdev->awb_speed = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + + r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, + AWB_CONTROL_DELAY_FORMATTER, &def); + if (r || def > 63) + def = 0; + cfg = pwc_awb_delay_cfg; + cfg.def = def; + pdev->awb_delay = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + if (!(pdev->features & FEATURE_MOTOR_PANTILT)) return hdl->error; @@ -357,25 +395,16 @@ int pwc_init_controls(struct pwc_device *pdev) return hdl->error; } -static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) +static void pwc_vidioc_fill_fmt(struct v4l2_format *f, + int width, int height, u32 pixfmt) { memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); - f->fmt.pix.width = pdev->view.x; - f->fmt.pix.height = pdev->view.y; + f->fmt.pix.width = width; + f->fmt.pix.height = height; f->fmt.pix.field = V4L2_FIELD_NONE; - if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; - f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - } else { - /* vbandlength contains 4 lines ... */ - f->fmt.pix.bytesperline = pdev->vbandlength/4; - f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame); - if (DEVICE_USE_CODEC1(pdev->type)) - f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1; - else - f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2; - } + f->fmt.pix.pixelformat = pixfmt; + f->fmt.pix.bytesperline = f->fmt.pix.width; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.width * 3 / 2; PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", f->fmt.pix.width, @@ -391,6 +420,8 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma /* ioctl(VIDIOC_TRY_FMT) */ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) { + int size; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); return -EINVAL; @@ -417,15 +448,11 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) } - if (f->fmt.pix.width > pdev->view_max.x) - f->fmt.pix.width = pdev->view_max.x; - else if (f->fmt.pix.width < pdev->view_min.x) - f->fmt.pix.width = pdev->view_min.x; - - if (f->fmt.pix.height > pdev->view_max.y) - f->fmt.pix.height = pdev->view_max.y; - else if (f->fmt.pix.height < pdev->view_min.y) - f->fmt.pix.height = pdev->view_min.y; + size = pwc_get_size(pdev, f->fmt.pix.width, f->fmt.pix.height); + pwc_vidioc_fill_fmt(f, + pwc_image_sizes[size][0], + pwc_image_sizes[size][1], + f->fmt.pix.pixelformat); return 0; } @@ -435,68 +462,50 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct pwc_device *pdev = video_drvdata(file); - int ret, fps, snapshot, compression, pixelformat; - - if (!pdev->udev) - return -ENODEV; + int ret, pixelformat, compression = 0; - if (pdev->capt_file != NULL && - pdev->capt_file != file) + if (pwc_test_n_set_capt_file(pdev, file)) return -EBUSY; - pdev->capt_file = file; - ret = pwc_vidioc_try_fmt(pdev, f); - if (ret<0) + if (ret < 0) return ret; pixelformat = f->fmt.pix.pixelformat; - compression = pdev->vcompression; - snapshot = 0; - fps = pdev->vframes; - if (f->fmt.pix.priv) { - compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT; - snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT); - fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; - if (fps == 0) - fps = pdev->vframes; - } - if (pixelformat != V4L2_PIX_FMT_YUV420 && - pixelformat != V4L2_PIX_FMT_PWC1 && - pixelformat != V4L2_PIX_FMT_PWC2) - return -EINVAL; + mutex_lock(&pdev->udevlock); + if (!pdev->udev) { + ret = -ENODEV; + goto leave; + } - if (vb2_is_streaming(&pdev->vb_queue)) - return -EBUSY; + if (pdev->iso_init) { + ret = -EBUSY; + goto leave; + } PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " - "compression=%d snapshot=%d format=%c%c%c%c\n", - f->fmt.pix.width, f->fmt.pix.height, fps, - compression, snapshot, + "format=%c%c%c%c\n", + f->fmt.pix.width, f->fmt.pix.height, pdev->vframes, (pixelformat)&255, (pixelformat>>8)&255, (pixelformat>>16)&255, (pixelformat>>24)&255); - ret = pwc_set_video_mode(pdev, - f->fmt.pix.width, - f->fmt.pix.height, - fps, - compression, - snapshot); + ret = pwc_set_video_mode(pdev, f->fmt.pix.width, f->fmt.pix.height, + pdev->vframes, &compression); PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret); - if (ret) - return ret; - - pdev->pixfmt = pixelformat; - - pwc_vidioc_fill_fmt(pdev, f); - - return 0; + if (ret == 0) { + pdev->pixfmt = pixelformat; + pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, + pdev->pixfmt); + } +leave: + mutex_unlock(&pdev->udevlock); + return ret; } static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) @@ -536,30 +545,14 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i) return i ? -EINVAL : 0; } -static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl) { struct pwc_device *pdev = container_of(ctrl->handler, struct pwc_device, ctrl_handler); int ret = 0; - /* - * Sometimes it can take quite long for the pwc to complete usb control - * transfers, so release the modlock to give streaming by another - * process / thread the chance to continue with a dqbuf. - */ - mutex_unlock(&pdev->modlock); - - /* - * Take the udev-lock to protect against the disconnect handler - * completing and setting dev->udev to NULL underneath us. Other code - * does not need to do this since it is protected by the modlock. - */ - mutex_lock(&pdev->udevlock); - - if (!pdev->udev) { - ret = -ENODEV; - goto leave; - } + if (!pdev->udev) + return -ENODEV; switch (ctrl->id) { case V4L2_CID_AUTO_WHITE_BALANCE: @@ -624,9 +617,18 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) if (ret) PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); -leave: + return ret; +} + +static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct pwc_device *pdev = + container_of(ctrl->handler, struct pwc_device, ctrl_handler); + int ret; + + mutex_lock(&pdev->udevlock); + ret = pwc_g_volatile_ctrl_unlocked(ctrl); mutex_unlock(&pdev->udevlock); - mutex_lock(&pdev->modlock); return ret; } @@ -643,6 +645,15 @@ static int pwc_set_awb(struct pwc_device *pdev) if (pdev->auto_white_balance->val != awb_manual) pdev->color_bal_valid = false; /* Force cache update */ + + /* + * If this is a preset, update our red / blue balance values + * so that events get generated for the new preset values + */ + if (pdev->auto_white_balance->val == awb_indoor || + pdev->auto_white_balance->val == awb_outdoor || + pdev->auto_white_balance->val == awb_fl) + pwc_g_volatile_ctrl_unlocked(pdev->auto_white_balance); } if (pdev->auto_white_balance->val != awb_manual) return 0; @@ -806,8 +817,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) container_of(ctrl->handler, struct pwc_device, ctrl_handler); int ret = 0; - /* See the comments on locking in pwc_g_volatile_ctrl */ - mutex_unlock(&pdev->modlock); mutex_lock(&pdev->udevlock); if (!pdev->udev) { @@ -891,6 +900,16 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); break; + case PWC_CID_CUSTOM(awb_speed): + ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, + AWB_CONTROL_SPEED_FORMATTER, + ctrl->val); + break; + case PWC_CID_CUSTOM(awb_delay): + ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, + AWB_CONTROL_DELAY_FORMATTER, + ctrl->val); + break; case V4L2_CID_PAN_RELATIVE: ret = pwc_set_motor(pdev); break; @@ -903,7 +922,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) leave: mutex_unlock(&pdev->udevlock); - mutex_lock(&pdev->modlock); return ret; } @@ -933,9 +951,14 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct pwc_device *pdev = video_drvdata(file); + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */ PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", - pdev->image.x, pdev->image.y); - pwc_vidioc_fill_fmt(pdev, f); + pdev->width, pdev->height); + pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt); + mutex_unlock(&pdev->udevlock); return 0; } @@ -951,12 +974,9 @@ static int pwc_reqbufs(struct file *file, void *fh, { struct pwc_device *pdev = video_drvdata(file); - if (pdev->capt_file != NULL && - pdev->capt_file != file) + if (pwc_test_n_set_capt_file(pdev, file)) return -EBUSY; - pdev->capt_file = file; - return vb2_reqbufs(&pdev->vb_queue, rb); } @@ -1025,25 +1045,21 @@ static int pwc_enum_framesizes(struct file *file, void *fh, struct pwc_device *pdev = video_drvdata(file); unsigned int i = 0, index = fsize->index; - if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { + if (fsize->pixel_format == V4L2_PIX_FMT_YUV420 || + (fsize->pixel_format == V4L2_PIX_FMT_PWC1 && + DEVICE_USE_CODEC1(pdev->type)) || + (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && + DEVICE_USE_CODEC23(pdev->type))) { for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1UL << i)) { - if (!index--) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pwc_image_sizes[i].x; - fsize->discrete.height = pwc_image_sizes[i].y; - return 0; - } + if (!(pdev->image_mask & (1UL << i))) + continue; + if (!index--) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = pwc_image_sizes[i][0]; + fsize->discrete.height = pwc_image_sizes[i][1]; + return 0; } } - } else if (fsize->index == 0 && - ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || - (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pdev->abs_max.x; - fsize->discrete.height = pdev->abs_max.y; - return 0; } return -EINVAL; } @@ -1056,8 +1072,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh, unsigned int i; for (i = 0; i < PSZ_MAX; i++) { - if (pwc_image_sizes[i].x == fival->width && - pwc_image_sizes[i].y == fival->height) { + if (pwc_image_sizes[i][0] == fival->width && + pwc_image_sizes[i][1] == fival->height) { size = i; break; } @@ -1086,14 +1102,6 @@ static int pwc_log_status(struct file *file, void *priv) return 0; } -static long pwc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct pwc_device *pdev = video_drvdata(file); - - return pwc_ioctl(pdev, cmd, arg); -} - const struct v4l2_ioctl_ops pwc_ioctl_ops = { .vidioc_querycap = pwc_querycap, .vidioc_enum_input = pwc_enum_input, @@ -1112,8 +1120,4 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { .vidioc_log_status = pwc_log_status, .vidioc_enum_framesizes = pwc_enum_framesizes, .vidioc_enum_frameintervals = pwc_enum_frameintervals, - .vidioc_default = pwc_default, }; - - -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 0e4e2d7b7872..47c518fef179 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -35,15 +35,16 @@ #include <asm/errno.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> #include <media/videobuf2-vmalloc.h> #ifdef CONFIG_USB_PWC_INPUT_EVDEV #include <linux/input.h> #endif -#include <media/pwc-ioctl.h> - /* Version block */ #define PWC_VERSION "10.0.15" #define PWC_NAME "pwc" @@ -106,6 +107,9 @@ #define FEATURE_CODEC1 0x0002 #define FEATURE_CODEC2 0x0004 +#define MAX_WIDTH 640 +#define MAX_HEIGHT 480 + /* Ignore errors in the first N frames, to allow for startup delays */ #define FRAME_LOWMARK 5 @@ -186,6 +190,24 @@ #define PT_RESET_CONTROL_FORMATTER 0x02 #define PT_STATUS_FORMATTER 0x03 +/* Enumeration of image sizes */ +#define PSZ_SQCIF 0x00 +#define PSZ_QSIF 0x01 +#define PSZ_QCIF 0x02 +#define PSZ_SIF 0x03 +#define PSZ_CIF 0x04 +#define PSZ_VGA 0x05 +#define PSZ_MAX 6 + +struct pwc_raw_frame { + __le16 type; /* type of the webcam */ + __le16 vbandlength; /* Size of 4 lines compressed (used by the + decompressor) */ + __u8 cmd[4]; /* the four byte of the command (in case of + nala, only the first 3 bytes is filled) */ + __u8 rawframe[0]; /* frame_size = H / 4 * vbandlength */ +} __packed; + /* intermediate buffers with raw data from the USB cam */ struct pwc_frame_buf { @@ -198,33 +220,30 @@ struct pwc_frame_buf struct pwc_device { struct video_device vdev; - struct mutex modlock; + struct v4l2_device v4l2_dev; /* Pointer to our usb_device, may be NULL after unplug */ struct usb_device *udev; - /* Protects the setting of udev to NULL by our disconnect handler */ struct mutex udevlock; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ int type; int release; /* release number */ int features; /* feature bits */ - char serial[30]; /* serial number (string) */ /*** Video data ***/ struct file *capt_file; /* file doing video capture */ + struct mutex capt_file_lock; int vendpoint; /* video isoc endpoint */ int vcinterface; /* video control interface */ int valternate; /* alternate interface needed */ - int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ + int vframes; /* frames-per-second */ int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */ int vframe_count; /* received frames */ int vmax_packet_size; /* USB maxpacket size */ int vlast_packet_size; /* for frame synchronisation */ int visoc_errors; /* number of contiguous ISOC errors */ - int vcompression; /* desired compression factor */ int vbandlength; /* compressed band length; 0 is uncompressed */ - char vsnapshot; /* snapshot mode */ char vsync; /* used by isoc handler */ char vmirror; /* for ToUCaM series */ char power_save; /* Do powersaving for this cam */ @@ -262,21 +281,8 @@ struct pwc_device * a gray or black border. view_min <= image <= view <= view_max; */ int image_mask; /* supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum view */ - struct pwc_coord abs_max; /* maximum supported size */ - struct pwc_coord image, view; /* image and viewport size */ - struct pwc_coord offset; /* offset of the viewport */ - - /*** motorized pan/tilt feature */ - struct pwc_mpt_range angle_range; - int pan_angle; /* in degrees * 100 */ - int tilt_angle; /* absolute angle; 0,0 is home */ + int width, height; /* current resolution */ - /* - * Set to 1 when the user push the button, reset to 0 - * when this value is read from sysfs. - */ - int snapshot_button_status; #ifdef CONFIG_USB_PWC_INPUT_EVDEV struct input_dev *button_dev; /* webcam snapshot button input */ char button_phys[64]; @@ -328,6 +334,8 @@ struct pwc_device struct v4l2_ctrl *save_user; struct v4l2_ctrl *restore_user; struct v4l2_ctrl *restore_factory; + struct v4l2_ctrl *awb_speed; + struct v4l2_ctrl *awb_delay; struct { /* motor control cluster */ struct v4l2_ctrl *motor_pan; @@ -344,19 +352,20 @@ struct pwc_device extern int pwc_trace; #endif +int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file); + /** Functions in pwc-misc.c */ /* sizes in pixels */ -extern const struct pwc_coord pwc_image_sizes[PSZ_MAX]; +extern const int pwc_image_sizes[PSZ_MAX][2]; -int pwc_decode_size(struct pwc_device *pdev, int width, int height); +int pwc_get_size(struct pwc_device *pdev, int width, int height); void pwc_construct(struct pwc_device *pdev); /** Functions in pwc-ctrl.c */ /* Request a certain video mode. Returns < 0 if not possible */ -extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); +extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, + int frames, int *compression); extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); -extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); -extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); extern int send_control_msg(struct pwc_device *pdev, @@ -375,9 +384,6 @@ int pwc_init_controls(struct pwc_device *pdev); /* Power down or up the camera; not supported by all models */ extern void pwc_camera_power(struct pwc_device *pdev, int power); -/* Private ioctl()s; see pwc-ioctl.h */ -extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); - extern const struct v4l2_ioctl_ops pwc_ioctl_ops; /** pwc-uncompress.c */ diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 79fb22c89ae9..0bd7da26d018 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -1133,12 +1133,13 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, __raw_writel(cicr0, pcdev->base + CICR0); } -static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int pxa_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 pxa_camera_dev *pcdev = 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; int ret; struct pxa_cam *cam = icd->host_priv; @@ -1851,19 +1852,7 @@ static struct platform_driver pxa_camera_driver = { .remove = __devexit_p(pxa_camera_remove), }; - -static int __init pxa_camera_init(void) -{ - return platform_driver_register(&pxa_camera_driver); -} - -static void __exit pxa_camera_exit(void) -{ - platform_driver_unregister(&pxa_camera_driver); -} - -module_init(pxa_camera_init); -module_exit(pxa_camera_exit); +module_platform_driver(pxa_camera_driver); MODULE_DESCRIPTION("PXA27x SoC Camera Host driver"); MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 2cc3b9166724..510cfab477ff 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -63,6 +63,8 @@ static int fimc_init_capture(struct fimc_dev *fimc) fimc_hw_set_effect(ctx, false); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); + if (fimc->variant->has_alpha) + fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock_irqrestore(&fimc->slock, flags); @@ -154,6 +156,8 @@ int fimc_capture_config_update(struct fimc_ctx *ctx) fimc_hw_set_rotation(ctx); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_hw_set_out_dma(ctx); + if (fimc->variant->has_alpha) + fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock(&ctx->slock); @@ -812,6 +816,10 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) FIMC_SD_PAD_SOURCE); if (!ff->fmt) return -EINVAL; + + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + /* Try to match format at the host and the sensor */ if (!fimc->vid_cap.user_subdev_api) { mf->code = ff->fmt->mbus_code; @@ -1235,6 +1243,9 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, *mf = fmt->format; return 0; } + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); ff = fmt->pad == FIMC_SD_PAD_SINK ? diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 07c6254faee3..f5cbb8a4c540 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -52,13 +52,29 @@ static struct fimc_fmt fimc_formats[] = { .colplanes = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "XRGB-8-8-8-8, 32 bpp", + .name = "ARGB8888, 32 bpp", .fourcc = V4L2_PIX_FMT_RGB32, .depth = { 32 }, .color = S5P_FIMC_RGB888, .memplanes = 1, .colplanes = 1, - .flags = FMT_FLAGS_M2M, + .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA, + }, { + .name = "ARGB1555", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = { 16 }, + .color = S5P_FIMC_RGB555, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, + }, { + .name = "ARGB4444", + .fourcc = V4L2_PIX_FMT_RGB444, + .depth = { 16 }, + .color = S5P_FIMC_RGB444, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, }, { .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, @@ -171,6 +187,14 @@ static struct fimc_fmt fimc_formats[] = { }, }; +static unsigned int get_m2m_fmt_flags(unsigned int stream_type) +{ + if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return FMT_FLAGS_M2M_IN; + else + return FMT_FLAGS_M2M_OUT; +} + int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, int dw, int dh, int rotation) { @@ -652,8 +676,11 @@ static void fimc_dma_run(void *priv) if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS)) fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1); - if (ctx->state & FIMC_PARAMS) + if (ctx->state & FIMC_PARAMS) { fimc_hw_set_out_dma(ctx); + if (fimc->variant->has_alpha) + fimc_hw_set_rgb_alpha(ctx); + } fimc_activate_capture(ctx); @@ -750,12 +777,11 @@ static struct vb2_ops fimc_qops = { #define ctrl_to_ctx(__ctrl) \ container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler) -static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) +static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl) { - struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); struct fimc_dev *fimc = ctx->fimc_dev; struct samsung_fimc_variant *variant = fimc->variant; - unsigned long flags; + unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT; int ret = 0; if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) @@ -763,52 +789,63 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_HFLIP: - spin_lock_irqsave(&ctx->slock, flags); ctx->hflip = ctrl->val; break; case V4L2_CID_VFLIP: - spin_lock_irqsave(&ctx->slock, flags); ctx->vflip = ctrl->val; break; case V4L2_CID_ROTATE: if (fimc_capture_pending(fimc) || - fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { + (ctx->state & flags) == flags) { ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, ctx->s_frame.height, ctx->d_frame.width, ctx->d_frame.height, ctrl->val); - } - if (ret) { - v4l2_err(fimc->m2m.vfd, "Out of scaler range\n"); - return -EINVAL; + if (ret) + return -EINVAL; } if ((ctrl->val == 90 || ctrl->val == 270) && !variant->has_out_rot) return -EINVAL; - spin_lock_irqsave(&ctx->slock, flags); + ctx->rotation = ctrl->val; break; - default: - v4l2_err(fimc->v4l2_dev, "Invalid control: 0x%X\n", ctrl->id); - return -EINVAL; + case V4L2_CID_ALPHA_COMPONENT: + ctx->d_frame.alpha = ctrl->val; + break; } ctx->state |= FIMC_PARAMS; set_bit(ST_CAPT_APPLY_CFG, &fimc->state); - spin_unlock_irqrestore(&ctx->slock, flags); return 0; } +static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ctx->slock, flags); + ret = __fimc_s_ctrl(ctx, ctrl); + spin_unlock_irqrestore(&ctx->slock, flags); + + return ret; +} + static const struct v4l2_ctrl_ops fimc_ctrl_ops = { .s_ctrl = fimc_s_ctrl, }; int fimc_ctrls_create(struct fimc_ctx *ctx) { + struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; + unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt); + if (ctx->ctrls_rdy) return 0; - v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4); ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); @@ -816,6 +853,13 @@ int fimc_ctrls_create(struct fimc_ctx *ctx) V4L2_CID_VFLIP, 0, 1, 1, 0); ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); + if (variant->has_alpha) + ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, + 0, max_alpha, 1, 0); + else + ctx->ctrl_alpha = NULL; + ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; return ctx->ctrl_handler.error; @@ -826,11 +870,14 @@ void fimc_ctrls_delete(struct fimc_ctx *ctx) if (ctx->ctrls_rdy) { v4l2_ctrl_handler_free(&ctx->ctrl_handler); ctx->ctrls_rdy = false; + ctx->ctrl_alpha = NULL; } } void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) { + unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA; + if (!ctx->ctrls_rdy) return; @@ -838,6 +885,8 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) v4l2_ctrl_activate(ctx->ctrl_rotate, active); v4l2_ctrl_activate(ctx->ctrl_hflip, active); v4l2_ctrl_activate(ctx->ctrl_vflip, active); + if (ctx->ctrl_alpha) + v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha); if (active) { ctx->rotation = ctx->ctrl_rotate->val; @@ -851,6 +900,24 @@ void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) mutex_unlock(&ctx->ctrl_handler.lock); } +/* Update maximum value of the alpha color control */ +void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_ctrl *ctrl = ctx->ctrl_alpha; + + if (ctrl == NULL || !fimc->variant->has_alpha) + return; + + v4l2_ctrl_lock(ctrl); + ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt); + + if (ctrl->cur.val > ctrl->maximum) + ctrl->cur.val = ctrl->maximum; + + v4l2_ctrl_unlock(ctrl); +} + /* * V4L2 ioctl handlers */ @@ -874,7 +941,8 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, { struct fimc_fmt *fmt; - fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_M2M, f->index); + fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), + f->index); if (!fmt) return -EINVAL; @@ -938,6 +1006,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, pix->colorspace = V4L2_COLORSPACE_JPEG; pix->field = V4L2_FIELD_NONE; pix->num_planes = fmt->memplanes; + pix->pixelformat = fmt->fourcc; pix->height = height; pix->width = width; @@ -1017,7 +1086,8 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) dbg("w: %d, h: %d", pix->width, pix->height); - fmt = fimc_find_format(&pix->pixelformat, NULL, FMT_FLAGS_M2M, 0); + fmt = fimc_find_format(&pix->pixelformat, NULL, + get_m2m_fmt_flags(f->type), 0); if (WARN(fmt == NULL, "Pixel format lookup failed")) return -EINVAL; @@ -1087,10 +1157,13 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, pix = &f->fmt.pix_mp; frame->fmt = fimc_find_format(&pix->pixelformat, NULL, - FMT_FLAGS_M2M, 0); + get_m2m_fmt_flags(f->type), 0); if (!frame->fmt) return -EINVAL; + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + for (i = 0; i < frame->fmt->colplanes; i++) { frame->payload[i] = (pix->width * pix->height * frame->fmt->depth[i]) / 8; @@ -1374,6 +1447,12 @@ static int fimc_m2m_open(struct file *file) if (!ctx) return -ENOMEM; v4l2_fh_init(&ctx->fh, fimc->m2m.vfd); + ctx->fimc_dev = fimc; + + /* Default color format */ + ctx->s_frame.fmt = &fimc_formats[0]; + ctx->d_frame.fmt = &fimc_formats[0]; + ret = fimc_ctrls_create(ctx); if (ret) goto error_fh; @@ -1383,10 +1462,6 @@ static int fimc_m2m_open(struct file *file) file->private_data = &ctx->fh; v4l2_fh_add(&ctx->fh); - ctx->fimc_dev = fimc; - /* Default color format */ - ctx->s_frame.fmt = &fimc_formats[0]; - ctx->d_frame.fmt = &fimc_formats[0]; /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; ctx->flags = 0; @@ -1709,9 +1784,8 @@ static int fimc_runtime_resume(struct device *dev) /* Resume the capture or mem-to-mem device */ if (fimc_capture_busy(fimc)) return fimc_capture_resume(fimc); - else if (fimc_m2m_pending(fimc)) - return fimc_m2m_resume(fimc); - return 0; + + return fimc_m2m_resume(fimc); } static int fimc_runtime_suspend(struct device *dev) @@ -1893,6 +1967,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .has_cam_if = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, + .has_alpha = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, @@ -1906,6 +1981,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = { .has_cam_if = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, + .has_alpha = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index c7f01c47b20f..4e20560c73d4 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -85,7 +85,9 @@ enum fimc_datapath { }; enum fimc_color_fmt { - S5P_FIMC_RGB565 = 0x10, + S5P_FIMC_RGB444 = 0x10, + S5P_FIMC_RGB555, + S5P_FIMC_RGB565, S5P_FIMC_RGB666, S5P_FIMC_RGB888, S5P_FIMC_RGB30_LOCAL, @@ -160,8 +162,11 @@ struct fimc_fmt { u16 colplanes; u8 depth[VIDEO_MAX_PLANES]; u16 flags; -#define FMT_FLAGS_CAM (1 << 0) -#define FMT_FLAGS_M2M (1 << 1) +#define FMT_FLAGS_CAM (1 << 0) +#define FMT_FLAGS_M2M_IN (1 << 1) +#define FMT_FLAGS_M2M_OUT (1 << 2) +#define FMT_FLAGS_M2M (1 << 1 | 1 << 2) +#define FMT_HAS_ALPHA (1 << 3) }; /** @@ -283,6 +288,7 @@ struct fimc_frame { struct fimc_addr paddr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; + u8 alpha; }; /** @@ -387,6 +393,7 @@ struct samsung_fimc_variant { unsigned int has_cistatus2:1; unsigned int has_mainscaler_ext:1; unsigned int has_cam_if:1; + unsigned int has_alpha:1; struct fimc_pix_limit *pix_limit; u16 min_inp_pixsize; u16 min_out_pixsize; @@ -482,7 +489,8 @@ struct fimc_dev { * @ctrl_handler: v4l2 controls handler * @ctrl_rotate image rotation control * @ctrl_hflip horizontal flip control - * @ctrl_vflip vartical flip control + * @ctrl_vflip vertical flip control + * @ctrl_alpha RGB alpha control * @ctrls_rdy: true if the control handler is initialized */ struct fimc_ctx { @@ -509,6 +517,7 @@ struct fimc_ctx { struct v4l2_ctrl *ctrl_rotate; struct v4l2_ctrl *ctrl_hflip; struct v4l2_ctrl *ctrl_vflip; + struct v4l2_ctrl *ctrl_alpha; bool ctrls_rdy; }; @@ -578,6 +587,17 @@ static inline int tiled_fmt(struct fimc_fmt *fmt) return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } +/* Return the alpha component bit mask */ +static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) +{ + switch (fmt->color) { + case S5P_FIMC_RGB444: return 0x0f; + case S5P_FIMC_RGB555: return 0x01; + case S5P_FIMC_RGB888: return 0xff; + default: return 0; + }; +} + static inline void fimc_hw_clear_irq(struct fimc_dev *dev) { u32 cfg = readl(dev->regs + S5P_CIGCTRL); @@ -674,6 +694,7 @@ void fimc_hw_set_prescaler(struct fimc_ctx *ctx); void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx); void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active); +void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); @@ -695,6 +716,7 @@ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, int fimc_ctrls_create(struct fimc_ctx *ctx); void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); +void fimc_alpha_ctrl_update(struct fimc_ctx *ctx); int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f); void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, struct v4l2_pix_format_mplane *pix); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 44f5c2d1920b..15466d0529c1 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -117,7 +117,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) S5P_CITRGFMT_VSIZE_MASK); switch (frame->fmt->color) { - case S5P_FIMC_RGB565...S5P_FIMC_RGB888: + case S5P_FIMC_RGB444...S5P_FIMC_RGB888: cfg |= S5P_CITRGFMT_RGB; break; case S5P_FIMC_YCBCR420: @@ -175,6 +175,7 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx) struct fimc_dev *dev = ctx->fimc_dev; struct fimc_frame *frame = &ctx->d_frame; struct fimc_dma_offset *offset = &frame->dma_offset; + struct fimc_fmt *fmt = frame->fmt; /* Set the input dma offsets. */ cfg = 0; @@ -198,15 +199,22 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx) cfg = readl(dev->regs + S5P_CIOCTRL); cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | - S5P_CIOCTRL_YCBCR_PLANE_MASK); + S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK); - if (frame->fmt->colplanes == 1) + if (fmt->colplanes == 1) cfg |= ctx->out_order_1p; - else if (frame->fmt->colplanes == 2) + else if (fmt->colplanes == 2) cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; - else if (frame->fmt->colplanes == 3) + else if (fmt->colplanes == 3) cfg |= S5P_CIOCTRL_YCBCR_3PLANE; + if (fmt->color == S5P_FIMC_RGB565) + cfg |= S5P_CIOCTRL_RGB565; + else if (fmt->color == S5P_FIMC_RGB555) + cfg |= S5P_CIOCTRL_ARGB1555; + else if (fmt->color == S5P_FIMC_RGB444) + cfg |= S5P_CIOCTRL_ARGB4444; + writel(cfg, dev->regs + S5P_CIOCTRL); } @@ -278,22 +286,28 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx) if (sc->copy_mode) cfg |= S5P_CISCCTRL_ONE2ONE; - if (ctx->in_path == FIMC_DMA) { - if (src_frame->fmt->color == S5P_FIMC_RGB565) + switch (src_frame->fmt->color) { + case S5P_FIMC_RGB565: cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565; - else if (src_frame->fmt->color == S5P_FIMC_RGB666) + break; + case S5P_FIMC_RGB666: cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666; - else if (src_frame->fmt->color == S5P_FIMC_RGB888) + break; + case S5P_FIMC_RGB888: cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888; + break; + } } if (ctx->out_path == FIMC_DMA) { - if (dst_frame->fmt->color == S5P_FIMC_RGB565) + u32 color = dst_frame->fmt->color; + + if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565) cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565; - else if (dst_frame->fmt->color == S5P_FIMC_RGB666) + else if (color == S5P_FIMC_RGB666) cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666; - else if (dst_frame->fmt->color == S5P_FIMC_RGB888) + else if (color == S5P_FIMC_RGB888) cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; } else { cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888; @@ -379,6 +393,21 @@ void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active) writel(cfg, dev->regs + S5P_CIIMGEFF); } +void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->d_frame; + u32 cfg; + + if (!(frame->fmt->flags & FMT_HAS_ALPHA)) + return; + + cfg = readl(dev->regs + S5P_CIOCTRL); + cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK; + cfg |= (frame->alpha << 4); + writel(cfg, dev->regs + S5P_CIOCTRL); +} + static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c index 59d79bc2f58a..130335cf62fd 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.c +++ b/drivers/media/video/s5p-fimc/mipi-csis.c @@ -427,6 +427,23 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } +static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + format->colorspace = V4L2_COLORSPACE_JPEG; + format->code = s5pcsis_formats[0].code; + format->width = S5PCSIS_DEF_PIX_WIDTH; + format->height = S5PCSIS_DEF_PIX_HEIGHT; + format->field = V4L2_FIELD_NONE; + + return 0; +} + +static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = { + .open = s5pcsis_open, +}; + static struct v4l2_subdev_core_ops s5pcsis_core_ops = { .s_power = s5pcsis_s_power, }; @@ -544,8 +561,13 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); state->sd.owner = THIS_MODULE; strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); + state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; state->csis_fmt = &s5pcsis_formats[0]; + state->format.code = s5pcsis_formats[0].code; + state->format.width = S5PCSIS_DEF_PIX_WIDTH; + state->format.height = S5PCSIS_DEF_PIX_HEIGHT; + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&state->sd.entity, diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h index f5691336dd5c..2709286396e1 100644 --- a/drivers/media/video/s5p-fimc/mipi-csis.h +++ b/drivers/media/video/s5p-fimc/mipi-csis.h @@ -19,4 +19,7 @@ #define CSIS_PAD_SOURCE 1 #define CSIS_PADS_NUM 2 +#define S5PCSIS_DEF_PIX_WIDTH 640 +#define S5PCSIS_DEF_PIX_HEIGHT 480 + #endif diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index c8e3b94bd91d..c7a5bc51d571 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -107,6 +107,11 @@ #define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3) #define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3) #define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) +#define S5P_CIOCTRL_ALPHA_OUT_MASK (0xff << 4) +#define S5P_CIOCTRL_RGB16FMT_MASK (3 << 16) +#define S5P_CIOCTRL_RGB565 (0 << 16) +#define S5P_CIOCTRL_ARGB1555 (1 << 16) +#define S5P_CIOCTRL_ARGB4444 (2 << 16) #define S5P_CIOCTRL_ORDER2P_SHIFT (24) #define S5P_CIOCTRL_ORDER2P_MASK (3 << 24) #define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24) diff --git a/drivers/media/video/s5p-g2d/Makefile b/drivers/media/video/s5p-g2d/Makefile new file mode 100644 index 000000000000..2c48c416a804 --- /dev/null +++ b/drivers/media/video/s5p-g2d/Makefile @@ -0,0 +1,3 @@ +s5p-g2d-objs := g2d.o g2d-hw.o + +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d.o diff --git a/drivers/media/video/s5p-g2d/g2d-hw.c b/drivers/media/video/s5p-g2d/g2d-hw.c new file mode 100644 index 000000000000..39937cf03c88 --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d-hw.c @@ -0,0 +1,104 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + * + * 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 <linux/io.h> + +#include "g2d.h" +#include "g2d-regs.h" + +#define w(x, a) writel((x), d->regs + (a)) +#define r(a) readl(d->regs + (a)) + +/* g2d_reset clears all g2d registers */ +void g2d_reset(struct g2d_dev *d) +{ + w(1, SOFT_RESET_REG); +} + +void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f) +{ + u32 n; + + w(f->stride & 0xFFFF, SRC_STRIDE_REG); + + n = f->o_height & 0xFFF; + n <<= 16; + n |= f->o_width & 0xFFF; + w(n, SRC_LEFT_TOP_REG); + + n = f->bottom & 0xFFF; + n <<= 16; + n |= f->right & 0xFFF; + w(n, SRC_RIGHT_BOTTOM_REG); + + w(f->fmt->hw, SRC_COLOR_MODE_REG); +} + +void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a) +{ + w(a, SRC_BASE_ADDR_REG); +} + +void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f) +{ + u32 n; + + w(f->stride & 0xFFFF, DST_STRIDE_REG); + + n = f->o_height & 0xFFF; + n <<= 16; + n |= f->o_width & 0xFFF; + w(n, DST_LEFT_TOP_REG); + + n = f->bottom & 0xFFF; + n <<= 16; + n |= f->right & 0xFFF; + w(n, DST_RIGHT_BOTTOM_REG); + + w(f->fmt->hw, DST_COLOR_MODE_REG); +} + +void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a) +{ + w(a, DST_BASE_ADDR_REG); +} + +void g2d_set_rop4(struct g2d_dev *d, u32 r) +{ + w(r, ROP4_REG); +} + +u32 g2d_cmd_stretch(u32 e) +{ + e &= 1; + return e << 4; +} + +void g2d_set_cmd(struct g2d_dev *d, u32 c) +{ + w(c, BITBLT_COMMAND_REG); +} + +void g2d_start(struct g2d_dev *d) +{ + /* Clear cache */ + w(0x7, CACHECTL_REG); + /* Enable interrupt */ + w(1, INTEN_REG); + /* Start G2D engine */ + w(1, BITBLT_START_REG); +} + +void g2d_clear_int(struct g2d_dev *d) +{ + w(1, INTC_PEND_REG); +} diff --git a/drivers/media/video/s5p-g2d/g2d-regs.h b/drivers/media/video/s5p-g2d/g2d-regs.h new file mode 100644 index 000000000000..02e1cf50da4e --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d-regs.h @@ -0,0 +1,115 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + * + * 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 + */ + +/* General Registers */ +#define SOFT_RESET_REG 0x0000 /* Software reset reg */ +#define INTEN_REG 0x0004 /* Interrupt Enable reg */ +#define INTC_PEND_REG 0x000C /* Interrupt Control Pending reg */ +#define FIFO_STAT_REG 0x0010 /* Command FIFO Status reg */ +#define AXI_ID_MODE_REG 0x0014 /* AXI Read ID Mode reg */ +#define CACHECTL_REG 0x0018 /* Cache & Buffer clear reg */ +#define AXI_MODE_REG 0x001C /* AXI Mode reg */ + +/* Command Registers */ +#define BITBLT_START_REG 0x0100 /* BitBLT Start reg */ +#define BITBLT_COMMAND_REG 0x0104 /* Command reg for BitBLT */ + +/* Parameter Setting Registers (Rotate & Direction) */ +#define ROTATE_REG 0x0200 /* Rotation reg */ +#define SRC_MSK_DIRECT_REG 0x0204 /* Src and Mask Direction reg */ +#define DST_PAT_DIRECT_REG 0x0208 /* Dest and Pattern Direction reg */ + +/* Parameter Setting Registers (Src) */ +#define SRC_SELECT_REG 0x0300 /* Src Image Selection reg */ +#define SRC_BASE_ADDR_REG 0x0304 /* Src Image Base Address reg */ +#define SRC_STRIDE_REG 0x0308 /* Src Stride reg */ +#define SRC_COLOR_MODE_REG 0x030C /* Src Image Color Mode reg */ +#define SRC_LEFT_TOP_REG 0x0310 /* Src Left Top Coordinate reg */ +#define SRC_RIGHT_BOTTOM_REG 0x0314 /* Src Right Bottom Coordinate reg */ + +/* Parameter Setting Registers (Dest) */ +#define DST_SELECT_REG 0x0400 /* Dest Image Selection reg */ +#define DST_BASE_ADDR_REG 0x0404 /* Dest Image Base Address reg */ +#define DST_STRIDE_REG 0x0408 /* Dest Stride reg */ +#define DST_COLOR_MODE_REG 0x040C /* Dest Image Color Mode reg */ +#define DST_LEFT_TOP_REG 0x0410 /* Dest Left Top Coordinate reg */ +#define DST_RIGHT_BOTTOM_REG 0x0414 /* Dest Right Bottom Coordinate reg */ + +/* Parameter Setting Registers (Pattern) */ +#define PAT_BASE_ADDR_REG 0x0500 /* Pattern Image Base Address reg */ +#define PAT_SIZE_REG 0x0504 /* Pattern Image Size reg */ +#define PAT_COLOR_MODE_REG 0x0508 /* Pattern Image Color Mode reg */ +#define PAT_OFFSET_REG 0x050C /* Pattern Left Top Coordinate reg */ +#define PAT_STRIDE_REG 0x0510 /* Pattern Stride reg */ + +/* Parameter Setting Registers (Mask) */ +#define MASK_BASE_ADDR_REG 0x0520 /* Mask Base Address reg */ +#define MASK_STRIDE_REG 0x0524 /* Mask Stride reg */ + +/* Parameter Setting Registers (Clipping Window) */ +#define CW_LT_REG 0x0600 /* LeftTop coordinates of Clip Window */ +#define CW_RB_REG 0x0604 /* RightBottom coordinates of Clip + Window */ + +/* Parameter Setting Registers (ROP & Alpha Setting) */ +#define THIRD_OPERAND_REG 0x0610 /* Third Operand Selection reg */ +#define ROP4_REG 0x0614 /* Raster Operation reg */ +#define ALPHA_REG 0x0618 /* Alpha value, Fading offset value */ + +/* Parameter Setting Registers (Color) */ +#define FG_COLOR_REG 0x0700 /* Foreground Color reg */ +#define BG_COLOR_REG 0x0704 /* Background Color reg */ +#define BS_COLOR_REG 0x0708 /* Blue Screen Color reg */ + +/* Parameter Setting Registers (Color Key) */ +#define SRC_COLORKEY_CTRL_REG 0x0710 /* Src Colorkey control reg */ +#define SRC_COLORKEY_DR_MIN_REG 0x0714 /* Src Colorkey Decision Reference + Min reg */ +#define SRC_COLORKEY_DR_MAX_REG 0x0718 /* Src Colorkey Decision Reference + Max reg */ +#define DST_COLORKEY_CTRL_REG 0x071C /* Dest Colorkey control reg */ +#define DST_COLORKEY_DR_MIN_REG 0x0720 /* Dest Colorkey Decision Reference + Min reg */ +#define DST_COLORKEY_DR_MAX_REG 0x0724 /* Dest Colorkey Decision Reference + Max reg */ + +/* Color mode values */ + +#define ORDER_XRGB 0 +#define ORDER_RGBX 1 +#define ORDER_XBGR 2 +#define ORDER_BGRX 3 + +#define MODE_XRGB_8888 0 +#define MODE_ARGB_8888 1 +#define MODE_RGB_565 2 +#define MODE_XRGB_1555 3 +#define MODE_ARGB_1555 4 +#define MODE_XRGB_4444 5 +#define MODE_ARGB_4444 6 +#define MODE_PACKED_RGB_888 7 + +#define COLOR_MODE(o, m) (((o) << 4) | (m)) + +/* ROP4 operation values */ +#define ROP4_COPY 0xCCCC +#define ROP4_INVERT 0x3333 + +/* Hardware limits */ +#define MAX_WIDTH 8000 +#define MAX_HEIGHT 8000 + +#define G2D_TIMEOUT 500 + +#define DEFAULT_WIDTH 100 +#define DEFAULT_HEIGHT 100 + diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c new file mode 100644 index 000000000000..c40b0dde1883 --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d.c @@ -0,0 +1,810 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + * + * 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 <linux/module.h> +#include <linux/fs.h> +#include <linux/version.h> +#include <linux/timer.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/interrupt.h> + +#include <linux/platform_device.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "g2d.h" +#include "g2d-regs.h" + +#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh) + +static struct g2d_fmt formats[] = { + { + .name = "XRGB_8888", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888), + }, + { + .name = "RGB_565", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .hw = COLOR_MODE(ORDER_XRGB, MODE_RGB_565), + }, + { + .name = "XRGB_1555", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555), + }, + { + .name = "XRGB_4444", + .fourcc = V4L2_PIX_FMT_RGB444, + .depth = 16, + .hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444), + }, + { + .name = "PACKED_RGB_888", + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .hw = COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888), + }, +}; +#define NUM_FORMATS ARRAY_SIZE(formats) + +struct g2d_frame def_frame = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .c_width = DEFAULT_WIDTH, + .c_height = DEFAULT_HEIGHT, + .o_width = 0, + .o_height = 0, + .fmt = &formats[0], + .right = DEFAULT_WIDTH, + .bottom = DEFAULT_HEIGHT, +}; + +struct g2d_fmt *find_fmt(struct v4l2_format *f) +{ + unsigned int i; + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix.pixelformat) + return &formats[i]; + } + return NULL; +} + + +static struct g2d_frame *get_frame(struct g2d_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->in; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->out; + default: + return ERR_PTR(-EINVAL); + } +} + +static int g2d_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct g2d_ctx *ctx = vb2_get_drv_priv(vq); + struct g2d_frame *f = get_frame(ctx, vq->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + + sizes[0] = f->size; + *nplanes = 1; + alloc_ctxs[0] = ctx->dev->alloc_ctx; + + if (*nbuffers == 0) + *nbuffers = 1; + + return 0; +} + +static int g2d_buf_prepare(struct vb2_buffer *vb) +{ + struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + vb2_set_plane_payload(vb, 0, f->size); + return 0; +} + +static void g2d_buf_queue(struct vb2_buffer *vb) +{ + struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + + +static struct vb2_ops g2d_qops = { + .queue_setup = g2d_queue_setup, + .buf_prepare = g2d_buf_prepare, + .buf_queue = g2d_buf_queue, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct g2d_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->ops = &g2d_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->ops = &g2d_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + return vb2_queue_init(dst_vq); +} + +static int g2d_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, + ctrl_handler); + switch (ctrl->id) { + case V4L2_CID_COLORFX: + if (ctrl->val == V4L2_COLORFX_NEGATIVE) + ctx->rop = ROP4_INVERT; + else + ctx->rop = ROP4_COPY; + default: + v4l2_err(&ctx->dev->v4l2_dev, "unknown control\n"); + return -EINVAL; + } + return 0; +} + +static const struct v4l2_ctrl_ops g2d_ctrl_ops = { + .s_ctrl = g2d_s_ctrl, +}; + +int g2d_setup_ctrls(struct g2d_ctx *ctx) +{ + struct g2d_dev *dev = ctx->dev; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); + if (ctx->ctrl_handler.error) { + v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + + v4l2_ctrl_new_std_menu( + &ctx->ctrl_handler, + &g2d_ctrl_ops, + V4L2_CID_COLORFX, + V4L2_COLORFX_NEGATIVE, + ~((1 << V4L2_COLORFX_NONE) | (1 << V4L2_COLORFX_NEGATIVE)), + V4L2_COLORFX_NONE); + + if (ctx->ctrl_handler.error) { + v4l2_err(&dev->v4l2_dev, "v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + + return 0; +} + +static int g2d_open(struct file *file) +{ + struct g2d_dev *dev = video_drvdata(file); + struct g2d_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->dev = dev; + /* Set default formats */ + ctx->in = def_frame; + ctx->out = def_frame; + + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + ret = PTR_ERR(ctx->m2m_ctx); + kfree(ctx); + return ret; + } + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + g2d_setup_ctrls(ctx); + + /* Write the default values to the ctx struct */ + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + + v4l2_info(&dev->v4l2_dev, "instance opened\n"); + return 0; +} + +static int g2d_release(struct file *file) +{ + struct g2d_dev *dev = video_drvdata(file); + struct g2d_ctx *ctx = fh2ctx(file->private_data); + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + v4l2_info(&dev->v4l2_dev, "instance closed\n"); + return 0; +} + + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1); + strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1); + cap->bus_info[0] = 0; + cap->version = KERNEL_VERSION(1, 0, 0); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +{ + struct g2d_fmt *fmt; + if (f->index >= NUM_FORMATS) + return -EINVAL; + fmt = &formats[f->index]; + f->pixelformat = fmt->fourcc; + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct g2d_ctx *ctx = prv; + struct vb2_queue *vq; + struct g2d_frame *frm; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + frm = get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + + f->fmt.pix.width = frm->width; + f->fmt.pix.height = frm->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = frm->fmt->fourcc; + f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; + f->fmt.pix.sizeimage = frm->size; + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct g2d_fmt *fmt; + enum v4l2_field *field; + + fmt = find_fmt(f); + if (!fmt) + return -EINVAL; + + field = &f->fmt.pix.field; + if (*field == V4L2_FIELD_ANY) + *field = V4L2_FIELD_NONE; + else if (*field != V4L2_FIELD_NONE) + return -EINVAL; + + if (f->fmt.pix.width > MAX_WIDTH) + f->fmt.pix.width = MAX_WIDTH; + if (f->fmt.pix.height > MAX_HEIGHT) + f->fmt.pix.height = MAX_HEIGHT; + + if (f->fmt.pix.width < 1) + f->fmt.pix.width = 1; + if (f->fmt.pix.height < 1) + f->fmt.pix.height = 1; + + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct vb2_queue *vq; + struct g2d_frame *frm; + struct g2d_fmt *fmt; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. */ + ret = vidioc_try_fmt(file, prv, f); + if (ret) + return ret; + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); + return -EBUSY; + } + frm = get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + fmt = find_fmt(f); + if (!fmt) + return -EINVAL; + frm->width = f->fmt.pix.width; + frm->height = f->fmt.pix.height; + frm->size = f->fmt.pix.sizeimage; + /* Reset crop settings */ + frm->o_width = 0; + frm->o_height = 0; + frm->c_width = frm->width; + frm->c_height = frm->height; + frm->right = frm->width; + frm->bottom = frm->height; + frm->fmt = fmt; + frm->stride = f->fmt.pix.bytesperline; + return 0; +} + +static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait) +{ + struct g2d_ctx *ctx = fh2ctx(file->private_data); + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); +} + +static int g2d_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct g2d_ctx *ctx = fh2ctx(file->private_data); + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct g2d_ctx *ctx = priv; + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cr) +{ + struct g2d_ctx *ctx = priv; + struct g2d_frame *f; + + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + cr->bounds.left = 0; + cr->bounds.top = 0; + cr->bounds.width = f->width; + cr->bounds.height = f->height; + cr->defrect = cr->bounds; + return 0; +} + +static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr) +{ + struct g2d_ctx *ctx = prv; + struct g2d_frame *f; + + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + cr->c.left = f->o_height; + cr->c.top = f->o_width; + cr->c.width = f->c_width; + cr->c.height = f->c_height; + return 0; +} + +static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct g2d_frame *f; + + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + if (cr->c.top < 0 || cr->c.left < 0) { + v4l2_err(&dev->v4l2_dev, + "doesn't support negative values for top & left\n"); + return -EINVAL; + } + + return 0; +} + +static int vidioc_s_crop(struct file *file, void *prv, struct v4l2_crop *cr) +{ + struct g2d_ctx *ctx = prv; + struct g2d_frame *f; + int ret; + + ret = vidioc_try_crop(file, prv, cr); + if (ret) + return ret; + f = get_frame(ctx, cr->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + f->c_width = cr->c.width; + f->c_height = cr->c.height; + f->o_width = cr->c.left; + f->o_height = cr->c.top; + f->bottom = f->o_height + f->c_height; + f->right = f->o_width + f->c_width; + return 0; +} + +static void g2d_lock(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + mutex_lock(&dev->mutex); +} + +static void g2d_unlock(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + mutex_unlock(&dev->mutex); +} + +static void job_abort(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + int ret; + + if (dev->curr == 0) /* No job currently running */ + return; + + ret = wait_event_timeout(dev->irq_queue, + dev->curr == 0, + msecs_to_jiffies(G2D_TIMEOUT)); +} + +static void device_run(void *prv) +{ + struct g2d_ctx *ctx = prv; + struct g2d_dev *dev = ctx->dev; + struct vb2_buffer *src, *dst; + u32 cmd = 0; + + dev->curr = ctx; + + src = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + + clk_enable(dev->gate); + g2d_reset(dev); + + g2d_set_src_size(dev, &ctx->in); + g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); + + g2d_set_dst_size(dev, &ctx->out); + g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); + + g2d_set_rop4(dev, ctx->rop); + if (ctx->in.c_width != ctx->out.c_width || + ctx->in.c_height != ctx->out.c_height) + cmd |= g2d_cmd_stretch(1); + g2d_set_cmd(dev, cmd); + g2d_start(dev); +} + +static irqreturn_t g2d_isr(int irq, void *prv) +{ + struct g2d_dev *dev = prv; + struct g2d_ctx *ctx = dev->curr; + struct vb2_buffer *src, *dst; + + g2d_clear_int(dev); + clk_disable(dev->gate); + + BUG_ON(ctx == 0); + + src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + + BUG_ON(src == 0); + BUG_ON(dst == 0); + + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); + + dev->curr = 0; + wake_up(&dev->irq_queue); + return IRQ_HANDLED; +} + +static const struct v4l2_file_operations g2d_fops = { + .owner = THIS_MODULE, + .open = g2d_open, + .release = g2d_release, + .poll = g2d_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = g2d_mmap, +}; + +static const struct v4l2_ioctl_ops g2d_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + + .vidioc_g_crop = vidioc_g_crop, + .vidioc_s_crop = vidioc_s_crop, + .vidioc_cropcap = vidioc_cropcap, +}; + +static struct video_device g2d_videodev = { + .name = G2D_NAME, + .fops = &g2d_fops, + .ioctl_ops = &g2d_ioctl_ops, + .minor = -1, + .release = video_device_release, +}; + +static struct v4l2_m2m_ops g2d_m2m_ops = { + .device_run = device_run, + .job_abort = job_abort, + .lock = g2d_lock, + .unlock = g2d_unlock, +}; + +static int g2d_probe(struct platform_device *pdev) +{ + struct g2d_dev *dev; + struct video_device *vfd; + struct resource *res; + int ret = 0; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + spin_lock_init(&dev->irqlock); + mutex_init(&dev->mutex); + atomic_set(&dev->num_inst, 0); + init_waitqueue_head(&dev->irq_queue); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to find registers\n"); + ret = -ENOENT; + goto free_dev; + } + + dev->res_regs = request_mem_region(res->start, resource_size(res), + dev_name(&pdev->dev)); + + if (!dev->res_regs) { + dev_err(&pdev->dev, "failed to obtain register region\n"); + ret = -ENOENT; + goto free_dev; + } + + dev->regs = ioremap(res->start, resource_size(res)); + if (!dev->regs) { + dev_err(&pdev->dev, "failed to map registers\n"); + ret = -ENOENT; + goto rel_res_regs; + } + + dev->clk = clk_get(&pdev->dev, "sclk_fimg2d"); + if (IS_ERR_OR_NULL(dev->clk)) { + dev_err(&pdev->dev, "failed to get g2d clock\n"); + ret = -ENXIO; + goto unmap_regs; + } + + dev->gate = clk_get(&pdev->dev, "fimg2d"); + if (IS_ERR_OR_NULL(dev->gate)) { + dev_err(&pdev->dev, "failed to get g2d clock gate\n"); + ret = -ENXIO; + goto put_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "failed to find IRQ\n"); + ret = -ENXIO; + goto put_clk_gate; + } + + dev->irq = res->start; + + ret = request_irq(dev->irq, g2d_isr, 0, pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "failed to install IRQ\n"); + goto put_clk_gate; + } + + dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(dev->alloc_ctx)) { + ret = PTR_ERR(dev->alloc_ctx); + goto rel_irq; + } + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto alloc_ctx_cleanup; + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_v4l2_dev; + } + *vfd = g2d_videodev; + vfd->lock = &dev->mutex; + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto rel_vdev; + } + video_set_drvdata(vfd, dev); + snprintf(vfd->name, sizeof(vfd->name), "%s", g2d_videodev.name); + dev->vfd = vfd; + v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", + vfd->num); + platform_set_drvdata(pdev, dev); + dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dev->m2m_dev); + goto unreg_video_dev; + } + + def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; + + return 0; + +unreg_video_dev: + video_unregister_device(dev->vfd); +rel_vdev: + video_device_release(vfd); +unreg_v4l2_dev: + v4l2_device_unregister(&dev->v4l2_dev); +alloc_ctx_cleanup: + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); +rel_irq: + free_irq(dev->irq, dev); +put_clk_gate: + clk_put(dev->gate); +put_clk: + clk_put(dev->clk); +unmap_regs: + iounmap(dev->regs); +rel_res_regs: + release_resource(dev->res_regs); +free_dev: + kfree(dev); + return ret; +} + +static int g2d_remove(struct platform_device *pdev) +{ + struct g2d_dev *dev = (struct g2d_dev *)platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME); + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); + vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); + free_irq(dev->irq, dev); + clk_put(dev->gate); + clk_put(dev->clk); + iounmap(dev->regs); + release_resource(dev->res_regs); + kfree(dev); + return 0; +} + +static struct platform_driver g2d_pdrv = { + .probe = g2d_probe, + .remove = g2d_remove, + .driver = { + .name = G2D_NAME, + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(g2d_pdrv); + +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); +MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h new file mode 100644 index 000000000000..5eae90107bf8 --- /dev/null +++ b/drivers/media/video/s5p-g2d/g2d.h @@ -0,0 +1,83 @@ +/* + * Samsung S5P G2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + * + * 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 <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> + +#define G2D_NAME "s5p-g2d" + +struct g2d_dev { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + struct mutex mutex; + spinlock_t irqlock; + atomic_t num_inst; + struct vb2_alloc_ctx *alloc_ctx; + struct resource *res_regs; + void __iomem *regs; + struct clk *clk; + struct clk *gate; + struct g2d_ctx *curr; + int irq; + wait_queue_head_t irq_queue; +}; + +struct g2d_frame { + /* Original dimensions */ + u32 width; + u32 height; + /* Crop size */ + u32 c_width; + u32 c_height; + /* Offset */ + u32 o_width; + u32 o_height; + /* Image format */ + struct g2d_fmt *fmt; + /* Variables that can calculated once and reused */ + u32 stride; + u32 bottom; + u32 right; + u32 size; +}; + +struct g2d_ctx { + struct v4l2_fh fh; + struct g2d_dev *dev; + struct v4l2_m2m_ctx *m2m_ctx; + struct g2d_frame in; + struct g2d_frame out; + struct v4l2_ctrl_handler ctrl_handler; + u32 rop; +}; + +struct g2d_fmt { + char *name; + u32 fourcc; + int depth; + u32 hw; +}; + + +void g2d_reset(struct g2d_dev *d); +void g2d_set_src_size(struct g2d_dev *d, struct g2d_frame *f); +void g2d_set_src_addr(struct g2d_dev *d, dma_addr_t a); +void g2d_set_dst_size(struct g2d_dev *d, struct g2d_frame *f); +void g2d_set_dst_addr(struct g2d_dev *d, dma_addr_t a); +void g2d_start(struct g2d_dev *d); +void g2d_clear_int(struct g2d_dev *d); +void g2d_set_rop4(struct g2d_dev *d, u32 r); +u32 g2d_cmd_stretch(u32 e); +void g2d_set_cmd(struct g2d_dev *d, u32 c); + + diff --git a/drivers/media/video/s5p-jpeg/Makefile b/drivers/media/video/s5p-jpeg/Makefile new file mode 100644 index 000000000000..ddc2900d88a2 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/Makefile @@ -0,0 +1,2 @@ +s5p-jpeg-objs := jpeg-core.o +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) := s5p-jpeg.o diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c new file mode 100644 index 000000000000..f841a3e9845c --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-core.c @@ -0,0 +1,1481 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-core.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * 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 <linux/clk.h> +#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "jpeg-core.h" +#include "jpeg-hw.h" + +static struct s5p_jpeg_fmt formats_enc[] = { + { + .name = "YUV 4:2:0 planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, + .colplanes = 3, + .types = MEM2MEM_CAPTURE, + }, + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .colplanes = 1, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, + { + .name = "RGB565", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .colplanes = 1, + .types = MEM2MEM_OUTPUT, + }, +}; +#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc) + +static struct s5p_jpeg_fmt formats_dec[] = { + { + .name = "YUV 4:2:0 planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, + .colplanes = 3, + .h_align = 4, + .v_align = 4, + .types = MEM2MEM_CAPTURE, + }, + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .colplanes = 1, + .h_align = 4, + .v_align = 3, + .types = MEM2MEM_CAPTURE, + }, + { + .name = "JPEG JFIF", + .fourcc = V4L2_PIX_FMT_JPEG, + .colplanes = 1, + .types = MEM2MEM_OUTPUT, + }, +}; +#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec) + +static const unsigned char qtbl_luminance[4][64] = { + {/* level 1 - high quality */ + 8, 6, 6, 8, 12, 14, 16, 17, + 6, 6, 6, 8, 10, 13, 12, 15, + 6, 6, 7, 8, 13, 14, 18, 24, + 8, 8, 8, 14, 13, 19, 24, 35, + 12, 10, 13, 13, 20, 26, 34, 39, + 14, 13, 14, 19, 26, 34, 39, 39, + 16, 12, 18, 24, 34, 39, 39, 39, + 17, 15, 24, 35, 39, 39, 39, 39 + }, + {/* level 2 */ + 12, 8, 8, 12, 17, 21, 24, 23, + 8, 9, 9, 11, 15, 19, 18, 23, + 8, 9, 10, 12, 19, 20, 27, 36, + 12, 11, 12, 21, 20, 28, 36, 53, + 17, 15, 19, 20, 30, 39, 51, 59, + 21, 19, 20, 28, 39, 51, 59, 59, + 24, 18, 27, 36, 51, 59, 59, 59, + 23, 23, 36, 53, 59, 59, 59, 59 + }, + {/* level 3 */ + 16, 11, 11, 16, 23, 27, 31, 30, + 11, 12, 12, 15, 20, 23, 23, 30, + 11, 12, 13, 16, 23, 26, 35, 47, + 16, 15, 16, 23, 26, 37, 47, 64, + 23, 20, 23, 26, 39, 51, 64, 64, + 27, 23, 26, 37, 51, 64, 64, 64, + 31, 23, 35, 47, 64, 64, 64, 64, + 30, 30, 47, 64, 64, 64, 64, 64 + }, + {/*level 4 - low quality */ + 20, 16, 25, 39, 50, 46, 62, 68, + 16, 18, 23, 38, 38, 53, 65, 68, + 25, 23, 31, 38, 53, 65, 68, 68, + 39, 38, 38, 53, 65, 68, 68, 68, + 50, 38, 53, 65, 68, 68, 68, 68, + 46, 53, 65, 68, 68, 68, 68, 68, + 62, 65, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } +}; + +static const unsigned char qtbl_chrominance[4][64] = { + {/* level 1 - high quality */ + 9, 8, 9, 11, 14, 17, 19, 24, + 8, 10, 9, 11, 14, 13, 17, 22, + 9, 9, 13, 14, 13, 15, 23, 26, + 11, 11, 14, 14, 15, 20, 26, 33, + 14, 14, 13, 15, 20, 24, 33, 39, + 17, 13, 15, 20, 24, 32, 39, 39, + 19, 17, 23, 26, 33, 39, 39, 39, + 24, 22, 26, 33, 39, 39, 39, 39 + }, + {/* level 2 */ + 13, 11, 13, 16, 20, 20, 29, 37, + 11, 14, 14, 14, 16, 20, 26, 32, + 13, 14, 15, 17, 20, 23, 35, 40, + 16, 14, 17, 21, 23, 30, 40, 50, + 20, 16, 20, 23, 30, 37, 50, 59, + 20, 20, 23, 30, 37, 48, 59, 59, + 29, 26, 35, 40, 50, 59, 59, 59, + 37, 32, 40, 50, 59, 59, 59, 59 + }, + {/* level 3 */ + 17, 15, 17, 21, 20, 26, 38, 48, + 15, 19, 18, 17, 20, 26, 35, 43, + 17, 18, 20, 22, 26, 30, 46, 53, + 21, 17, 22, 28, 30, 39, 53, 64, + 20, 20, 26, 30, 39, 48, 64, 64, + 26, 26, 30, 39, 48, 63, 64, 64, + 38, 35, 46, 53, 64, 64, 64, 64, + 48, 43, 53, 64, 64, 64, 64, 64 + }, + {/*level 4 - low quality */ + 21, 25, 32, 38, 54, 68, 68, 68, + 25, 28, 24, 38, 54, 68, 68, 68, + 32, 24, 32, 43, 66, 68, 68, 68, + 38, 38, 43, 53, 68, 68, 68, 68, + 54, 54, 66, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68 + } +}; + +static const unsigned char hdctbl0[16] = { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +static const unsigned char hdctblg0[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb +}; +static const unsigned char hactbl0[16] = { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d +}; +static const unsigned char hactblg0[162] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa +}; + +static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl, + unsigned long tab, int len) +{ + int i; + + for (i = 0; i < len; i++) + writel((unsigned int)qtbl[i], regs + tab + (i * 0x04)); +} + +static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality) +{ + /* this driver fills quantisation table 0 with data for luma */ + jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0), + ARRAY_SIZE(qtbl_luminance[quality])); +} + +static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality) +{ + /* this driver fills quantisation table 1 with data for chroma */ + jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1), + ARRAY_SIZE(qtbl_chrominance[quality])); +} + +static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl, + unsigned long tab, int len) +{ + int i; + + for (i = 0; i < len; i++) + writel((unsigned int)htbl[i], regs + tab + (i * 0x04)); +} + +static inline void jpeg_set_hdctbl(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0)); +} + +static inline void jpeg_set_hdctblg(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0)); +} + +static inline void jpeg_set_hactbl(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0)); +} + +static inline void jpeg_set_hactblg(void __iomem *regs) +{ + /* this driver fills table 0 for this component */ + jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0)); +} + +/* + * ============================================================================ + * Device file operations + * ============================================================================ + */ + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, + __u32 pixelformat); + +static int s5p_jpeg_open(struct file *file) +{ + struct s5p_jpeg *jpeg = video_drvdata(file); + struct video_device *vfd = video_devdata(file); + struct s5p_jpeg_ctx *ctx; + struct s5p_jpeg_fmt *out_fmt; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + file->private_data = ctx; + ctx->jpeg = jpeg; + if (vfd == jpeg->vfd_encoder) { + ctx->mode = S5P_JPEG_ENCODE; + out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565); + } else { + ctx->mode = S5P_JPEG_DECODE; + out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG); + } + + ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + int err = PTR_ERR(ctx->m2m_ctx); + kfree(ctx); + return err; + } + + ctx->out_q.fmt = out_fmt; + ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV); + + return 0; +} + +static int s5p_jpeg_release(struct file *file) +{ + struct s5p_jpeg_ctx *ctx = file->private_data; + + v4l2_m2m_ctx_release(ctx->m2m_ctx); + kfree(ctx); + + return 0; +} + +static unsigned int s5p_jpeg_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct s5p_jpeg_ctx *ctx = file->private_data; + + return v4l2_m2m_poll(file, ctx->m2m_ctx, wait); +} + +static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct s5p_jpeg_ctx *ctx = file->private_data; + + return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); +} + +static const struct v4l2_file_operations s5p_jpeg_fops = { + .owner = THIS_MODULE, + .open = s5p_jpeg_open, + .release = s5p_jpeg_release, + .poll = s5p_jpeg_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = s5p_jpeg_mmap, +}; + +/* + * ============================================================================ + * video ioctl operations + * ============================================================================ + */ + +static int get_byte(struct s5p_jpeg_buffer *buf) +{ + if (buf->curr >= buf->size) + return -1; + + return ((unsigned char *)buf->data)[buf->curr++]; +} + +static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word) +{ + unsigned int temp; + int byte; + + byte = get_byte(buf); + if (byte == -1) + return -1; + temp = byte << 8; + byte = get_byte(buf); + if (byte == -1) + return -1; + *word = (unsigned int)byte | temp; + return 0; +} + +static void skip(struct s5p_jpeg_buffer *buf, long len) +{ + if (len <= 0) + return; + + while (len--) + get_byte(buf); +} + +static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, + unsigned long buffer, unsigned long size) +{ + int c, components, notfound; + unsigned int height, width, word; + long length; + struct s5p_jpeg_buffer jpeg_buffer; + + jpeg_buffer.size = size; + jpeg_buffer.data = buffer; + jpeg_buffer.curr = 0; + + notfound = 1; + while (notfound) { + c = get_byte(&jpeg_buffer); + if (c == -1) + break; + if (c != 0xff) + continue; + do + c = get_byte(&jpeg_buffer); + while (c == 0xff); + if (c == -1) + break; + if (c == 0) + continue; + length = 0; + switch (c) { + /* SOF0: baseline JPEG */ + case SOF0: + if (get_word_be(&jpeg_buffer, &word)) + break; + if (get_byte(&jpeg_buffer) == -1) + break; + if (get_word_be(&jpeg_buffer, &height)) + break; + if (get_word_be(&jpeg_buffer, &width)) + break; + components = get_byte(&jpeg_buffer); + if (components == -1) + break; + notfound = 0; + + skip(&jpeg_buffer, components * 3); + break; + + /* skip payload-less markers */ + case RST ... RST + 7: + case SOI: + case EOI: + case TEM: + break; + + /* skip uninteresting payload markers */ + default: + if (get_word_be(&jpeg_buffer, &word)) + break; + length = (long)word - 2; + skip(&jpeg_buffer, length); + break; + } + } + result->w = width; + result->h = height; + result->size = components; + return !notfound; +} + +static int s5p_jpeg_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_ENCODE) { + strlcpy(cap->driver, S5P_JPEG_M2M_NAME " encoder", + sizeof(cap->driver)); + strlcpy(cap->card, S5P_JPEG_M2M_NAME " encoder", + sizeof(cap->card)); + } else { + strlcpy(cap->driver, S5P_JPEG_M2M_NAME " decoder", + sizeof(cap->driver)); + strlcpy(cap->card, S5P_JPEG_M2M_NAME " decoder", + sizeof(cap->card)); + } + cap->bus_info[0] = 0; + cap->capabilities = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OUTPUT; + return 0; +} + +static int enum_fmt(struct s5p_jpeg_fmt *formats, int n, + struct v4l2_fmtdesc *f, u32 type) +{ + int i, num = 0; + + for (i = 0; i < n; ++i) { + if (formats[i].types & type) { + /* index-th format of type type found ? */ + if (num == f->index) + break; + /* Correct type but haven't reached our index yet, + * just increment per-type index */ + ++num; + } + } + + /* Format not found */ + if (i >= n) + return -EINVAL; + + strlcpy(f->description, formats[i].name, sizeof(f->description)); + f->pixelformat = formats[i].fourcc; + + return 0; +} + +static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct s5p_jpeg_ctx *ctx; + + ctx = priv; + + if (ctx->mode == S5P_JPEG_ENCODE) + return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, + MEM2MEM_CAPTURE); + + return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE); +} + +static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct s5p_jpeg_ctx *ctx; + + ctx = priv; + + if (ctx->mode == S5P_JPEG_ENCODE) + return enum_fmt(formats_enc, NUM_FORMATS_ENC, f, + MEM2MEM_OUTPUT); + + return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT); +} + +static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, + enum v4l2_buf_type type) +{ + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + return &ctx->out_q; + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return &ctx->cap_q; + + return NULL; +} + +static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct s5p_jpeg_q_data *q_data = NULL; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct s5p_jpeg_ctx *ct = priv; + + vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed) + return -EINVAL; + q_data = get_q_data(ct, f->type); + BUG_ON(q_data == NULL); + + pix->width = q_data->w; + pix->height = q_data->h; + pix->field = V4L2_FIELD_NONE; + pix->pixelformat = q_data->fmt->fourcc; + pix->bytesperline = 0; + if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) { + u32 bpl = q_data->w; + if (q_data->fmt->colplanes == 1) + bpl = (bpl * q_data->fmt->depth) >> 3; + pix->bytesperline = bpl; + } + pix->sizeimage = q_data->size; + + return 0; +} + +static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode, + u32 pixelformat) +{ + unsigned int k; + struct s5p_jpeg_fmt *formats; + int n; + + if (mode == S5P_JPEG_ENCODE) { + formats = formats_enc; + n = NUM_FORMATS_ENC; + } else { + formats = formats_dec; + n = NUM_FORMATS_DEC; + } + + for (k = 0; k < n; k++) { + struct s5p_jpeg_fmt *fmt = &formats[k]; + if (fmt->fourcc == pixelformat) + return fmt; + } + + return NULL; + +} + +static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, + unsigned int walign, + u32 *h, unsigned int hmin, unsigned int hmax, + unsigned int halign) +{ + int width, height, w_step, h_step; + + width = *w; + height = *h; + + w_step = 1 << walign; + h_step = 1 << halign; + v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0); + + if (*w < width && (*w + w_step) < wmax) + *w += w_step; + if (*h < height && (*h + h_step) < hmax) + *h += h_step; + +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, + struct s5p_jpeg_ctx *ctx, int q_type) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (pix->field == V4L2_FIELD_ANY) + pix->field = V4L2_FIELD_NONE; + else if (pix->field != V4L2_FIELD_NONE) + return -EINVAL; + + /* V4L2 specification suggests the driver corrects the format struct + * if any of the dimensions is unsupported */ + if (q_type == MEM2MEM_OUTPUT) + jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, 0, + &pix->height, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, 0); + else + jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, fmt->h_align, + &pix->height, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, fmt->v_align); + + if (fmt->fourcc == V4L2_PIX_FMT_JPEG) { + if (pix->sizeimage <= 0) + pix->sizeimage = PAGE_SIZE; + pix->bytesperline = 0; + } else { + u32 bpl = pix->bytesperline; + + if (fmt->colplanes > 1 && bpl < pix->width) + bpl = pix->width; /* planar */ + + if (fmt->colplanes == 1 && /* packed */ + (bpl << 3) * fmt->depth < pix->width) + bpl = (pix->width * fmt->depth) >> 3; + + pix->bytesperline = bpl; + pix->sizeimage = (pix->width * pix->height * fmt->depth) >> 3; + } + + return 0; +} + +static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s5p_jpeg_fmt *fmt; + struct s5p_jpeg_ctx *ctx = priv; + + fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); + if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { + v4l2_err(&ctx->jpeg->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE); +} + +static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct s5p_jpeg_fmt *fmt; + struct s5p_jpeg_ctx *ctx = priv; + + fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat); + if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { + v4l2_err(&ctx->jpeg->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT); +} + +static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct s5p_jpeg_q_data *q_data = NULL; + struct v4l2_pix_format *pix = &f->fmt.pix; + + vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ct, f->type); + BUG_ON(q_data == NULL); + + if (vb2_is_busy(vq)) { + v4l2_err(&ct->jpeg->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat); + q_data->w = pix->width; + q_data->h = pix->height; + if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) + q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; + else + q_data->size = pix->sizeimage; + + return 0; +} + +static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = s5p_jpeg_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return s5p_jpeg_s_fmt(priv, f); +} + +static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = s5p_jpeg_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + return s5p_jpeg_s_fmt(priv, f); +} + +static int s5p_jpeg_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int s5p_jpeg_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int s5p_jpeg_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int s5p_jpeg_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int s5p_jpeg_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_jpeg_ctx *ctx = priv; + + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +int s5p_jpeg_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* For JPEG blob active == default == bounds */ + switch (s->target) { + case V4L2_SEL_TGT_CROP_ACTIVE: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.width = ctx->out_q.w; + s->r.height = ctx->out_q.h; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.width = ctx->cap_q.w; + s->r.height = ctx->cap_q.h; + break; + default: + return -EINVAL; + } + s->r.left = 0; + s->r.top = 0; + return 0; +} + +static int s5p_jpeg_g_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *compr) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_DECODE) + return -ENOTTY; + + memset(compr, 0, sizeof(*compr)); + compr->quality = ctx->compr_quality; + + return 0; +} + +static int s5p_jpeg_s_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *compr) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_DECODE) + return -ENOTTY; + + compr->quality = clamp(compr->quality, S5P_JPEG_COMPR_QUAL_BEST, + S5P_JPEG_COMPR_QUAL_WORST); + + ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - compr->quality; + + return 0; +} + +static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = { + .vidioc_querycap = s5p_jpeg_querycap, + + .vidioc_enum_fmt_vid_cap = s5p_jpeg_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = s5p_jpeg_enum_fmt_vid_out, + + .vidioc_g_fmt_vid_cap = s5p_jpeg_g_fmt, + .vidioc_g_fmt_vid_out = s5p_jpeg_g_fmt, + + .vidioc_try_fmt_vid_cap = s5p_jpeg_try_fmt_vid_cap, + .vidioc_try_fmt_vid_out = s5p_jpeg_try_fmt_vid_out, + + .vidioc_s_fmt_vid_cap = s5p_jpeg_s_fmt_vid_cap, + .vidioc_s_fmt_vid_out = s5p_jpeg_s_fmt_vid_out, + + .vidioc_reqbufs = s5p_jpeg_reqbufs, + .vidioc_querybuf = s5p_jpeg_querybuf, + + .vidioc_qbuf = s5p_jpeg_qbuf, + .vidioc_dqbuf = s5p_jpeg_dqbuf, + + .vidioc_streamon = s5p_jpeg_streamon, + .vidioc_streamoff = s5p_jpeg_streamoff, + + .vidioc_g_selection = s5p_jpeg_g_selection, + + .vidioc_g_jpegcomp = s5p_jpeg_g_jpegcomp, + .vidioc_s_jpegcomp = s5p_jpeg_s_jpegcomp, +}; + +/* + * ============================================================================ + * mem2mem callbacks + * ============================================================================ + */ + +static void s5p_jpeg_device_run(void *priv) +{ + struct s5p_jpeg_ctx *ctx = priv; + struct s5p_jpeg *jpeg = ctx->jpeg; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long src_addr, dst_addr; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + + jpeg_reset(jpeg->regs); + jpeg_poweron(jpeg->regs); + jpeg_proc_mode(jpeg->regs, ctx->mode); + if (ctx->mode == S5P_JPEG_ENCODE) { + if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565) + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565); + else + jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422); + if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV) + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_422); + else + jpeg_subsampling_mode(jpeg->regs, + S5P_JPEG_SUBSAMPLING_420); + jpeg_dri(jpeg->regs, 0); + jpeg_x(jpeg->regs, ctx->out_q.w); + jpeg_y(jpeg->regs, ctx->out_q.h); + jpeg_imgadr(jpeg->regs, src_addr); + jpeg_jpgadr(jpeg->regs, dst_addr); + + /* ultimately comes from sizeimage from userspace */ + jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size); + + /* JPEG RGB to YCbCr conversion matrix */ + jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11); + jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12); + jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13); + jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21); + jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22); + jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23); + jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31); + jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32); + jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33); + + /* + * JPEG IP allows storing 4 quantization tables + * We fill table 0 for luma and table 1 for chroma + */ + jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality); + jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality); + /* use table 0 for Y */ + jpeg_qtbl(jpeg->regs, 1, 0); + /* use table 1 for Cb and Cr*/ + jpeg_qtbl(jpeg->regs, 2, 1); + jpeg_qtbl(jpeg->regs, 3, 1); + + /* Y, Cb, Cr use Huffman table 0 */ + jpeg_htbl_ac(jpeg->regs, 1); + jpeg_htbl_dc(jpeg->regs, 1); + jpeg_htbl_ac(jpeg->regs, 2); + jpeg_htbl_dc(jpeg->regs, 2); + jpeg_htbl_ac(jpeg->regs, 3); + jpeg_htbl_dc(jpeg->regs, 3); + } else { + jpeg_rst_int_enable(jpeg->regs, true); + jpeg_data_num_int_enable(jpeg->regs, true); + jpeg_final_mcu_num_int_enable(jpeg->regs, true); + jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422); + jpeg_jpgadr(jpeg->regs, src_addr); + jpeg_imgadr(jpeg->regs, dst_addr); + } + jpeg_start(jpeg->regs); +} + +static int s5p_jpeg_job_ready(void *priv) +{ + struct s5p_jpeg_ctx *ctx = priv; + + if (ctx->mode == S5P_JPEG_DECODE) + return ctx->hdr_parsed; + return 1; +} + +static void s5p_jpeg_job_abort(void *priv) +{ +} + +static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = { + .device_run = s5p_jpeg_device_run, + .job_ready = s5p_jpeg_job_ready, + .job_abort = s5p_jpeg_job_abort, +}; + +/* + * ============================================================================ + * Queue operations + * ============================================================================ + */ + +static int s5p_jpeg_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + void *alloc_ctxs[]) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); + struct s5p_jpeg_q_data *q_data = NULL; + unsigned int size, count = *nbuffers; + + q_data = get_q_data(ctx, vq->type); + BUG_ON(q_data == NULL); + + size = q_data->size; + + /* + * header is parsed during decoding and parsed information stored + * in the context so we do not allow another buffer to overwrite it + */ + if (ctx->mode == S5P_JPEG_DECODE) + count = 1; + + *nbuffers = count; + *nplanes = 1; + sizes[0] = size; + alloc_ctxs[0] = ctx->jpeg->alloc_ctx; + + return 0; +} + +static int s5p_jpeg_buf_prepare(struct vb2_buffer *vb) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct s5p_jpeg_q_data *q_data = NULL; + + q_data = get_q_data(ctx, vb->vb2_queue->type); + BUG_ON(q_data == NULL); + + if (vb2_plane_size(vb, 0) < q_data->size) { + pr_err("%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, q_data->size); + + return 0; +} + +static void s5p_jpeg_buf_queue(struct vb2_buffer *vb) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + if (ctx->mode == S5P_JPEG_DECODE && + vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct s5p_jpeg_q_data tmp, *q_data; + ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp, + (unsigned long)vb2_plane_vaddr(vb, 0), + min((unsigned long)ctx->out_q.size, + vb2_get_plane_payload(vb, 0))); + if (!ctx->hdr_parsed) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + return; + } + + q_data = &ctx->out_q; + q_data->w = tmp.w; + q_data->h = tmp.h; + + q_data = &ctx->cap_q; + q_data->w = tmp.w; + q_data->h = tmp.h; + + jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH, + S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align, + &q_data->h, S5P_JPEG_MIN_HEIGHT, + S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align + ); + q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3; + } + if (ctx->m2m_ctx) + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + +static void s5p_jpeg_wait_prepare(struct vb2_queue *vq) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); + + mutex_unlock(&ctx->jpeg->lock); +} + +static void s5p_jpeg_wait_finish(struct vb2_queue *vq) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq); + + mutex_lock(&ctx->jpeg->lock); +} + +static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q); + int ret; + + ret = pm_runtime_get_sync(ctx->jpeg->dev); + + return ret > 0 ? 0 : ret; +} + +static int s5p_jpeg_stop_streaming(struct vb2_queue *q) +{ + struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q); + + pm_runtime_put(ctx->jpeg->dev); + + return 0; +} + +static struct vb2_ops s5p_jpeg_qops = { + .queue_setup = s5p_jpeg_queue_setup, + .buf_prepare = s5p_jpeg_buf_prepare, + .buf_queue = s5p_jpeg_buf_queue, + .wait_prepare = s5p_jpeg_wait_prepare, + .wait_finish = s5p_jpeg_wait_finish, + .start_streaming = s5p_jpeg_start_streaming, + .stop_streaming = s5p_jpeg_stop_streaming, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct s5p_jpeg_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &s5p_jpeg_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &s5p_jpeg_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + + return vb2_queue_init(dst_vq); +} + +/* + * ============================================================================ + * ISR + * ============================================================================ + */ + +static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) +{ + struct s5p_jpeg *jpeg = dev_id; + struct s5p_jpeg_ctx *curr_ctx; + struct vb2_buffer *src_buf, *dst_buf; + unsigned long payload_size = 0; + enum vb2_buffer_state state = VB2_BUF_STATE_DONE; + bool enc_jpeg_too_large = false; + bool timer_elapsed = false; + bool op_completed = false; + + curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + + src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + + if (curr_ctx->mode == S5P_JPEG_ENCODE) + enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs); + timer_elapsed = jpeg_timer_stat(jpeg->regs); + op_completed = jpeg_result_stat_ok(jpeg->regs); + if (curr_ctx->mode == S5P_JPEG_DECODE) + op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs); + + if (enc_jpeg_too_large) { + state = VB2_BUF_STATE_ERROR; + jpeg_clear_enc_stream_stat(jpeg->regs); + } else if (timer_elapsed) { + state = VB2_BUF_STATE_ERROR; + jpeg_clear_timer_stat(jpeg->regs); + } else if (!op_completed) { + state = VB2_BUF_STATE_ERROR; + } else { + payload_size = jpeg_compressed_size(jpeg->regs); + } + + v4l2_m2m_buf_done(src_buf, state); + if (curr_ctx->mode == S5P_JPEG_ENCODE) + vb2_set_plane_payload(dst_buf, 0, payload_size); + v4l2_m2m_buf_done(dst_buf, state); + v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx); + + jpeg_clear_int(jpeg->regs); + + return IRQ_HANDLED; +} + +/* + * ============================================================================ + * Driver basic infrastructure + * ============================================================================ + */ + +static int s5p_jpeg_probe(struct platform_device *pdev) +{ + struct s5p_jpeg *jpeg; + struct resource *res; + int ret; + + /* JPEG IP abstraction struct */ + jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL); + if (!jpeg) + return -ENOMEM; + + mutex_init(&jpeg->lock); + jpeg->dev = &pdev->dev; + + /* memory-mapped registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "cannot find IO resource\n"); + ret = -ENOENT; + goto jpeg_alloc_rollback; + } + + jpeg->ioarea = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!jpeg->ioarea) { + dev_err(&pdev->dev, "cannot request IO\n"); + ret = -ENXIO; + goto jpeg_alloc_rollback; + } + + jpeg->regs = ioremap(res->start, resource_size(res)); + if (!jpeg->regs) { + dev_err(&pdev->dev, "cannot map IO\n"); + ret = -ENXIO; + goto mem_region_rollback; + } + + dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", + jpeg->regs, jpeg->ioarea, res); + + /* interrupt service routine registration */ + jpeg->irq = ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot find IRQ\n"); + goto ioremap_rollback; + } + + ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0, + dev_name(&pdev->dev), jpeg); + + if (ret) { + dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq); + goto ioremap_rollback; + } + + /* clocks */ + jpeg->clk = clk_get(&pdev->dev, "jpeg"); + if (IS_ERR(jpeg->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + ret = PTR_ERR(jpeg->clk); + goto request_irq_rollback; + } + dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); + clk_enable(jpeg->clk); + + /* v4l2 device */ + ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + goto clk_get_rollback; + } + + /* mem2mem device */ + jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops); + if (IS_ERR(jpeg->m2m_dev)) { + v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(jpeg->m2m_dev); + goto device_register_rollback; + } + + jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(jpeg->alloc_ctx)) { + v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n"); + ret = PTR_ERR(jpeg->alloc_ctx); + goto m2m_init_rollback; + } + + /* JPEG encoder /dev/videoX node */ + jpeg->vfd_encoder = video_device_alloc(); + if (!jpeg->vfd_encoder) { + v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto vb2_allocator_rollback; + } + strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME, + sizeof(jpeg->vfd_encoder->name)); + jpeg->vfd_encoder->fops = &s5p_jpeg_fops; + jpeg->vfd_encoder->ioctl_ops = &s5p_jpeg_ioctl_ops; + jpeg->vfd_encoder->minor = -1; + jpeg->vfd_encoder->release = video_device_release; + jpeg->vfd_encoder->lock = &jpeg->lock; + jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev; + + ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); + goto enc_vdev_alloc_rollback; + } + + video_set_drvdata(jpeg->vfd_encoder, jpeg); + v4l2_info(&jpeg->v4l2_dev, + "encoder device registered as /dev/video%d\n", + jpeg->vfd_encoder->num); + + /* JPEG decoder /dev/videoX node */ + jpeg->vfd_decoder = video_device_alloc(); + if (!jpeg->vfd_decoder) { + v4l2_err(&jpeg->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto enc_vdev_register_rollback; + } + strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME, + sizeof(jpeg->vfd_decoder->name)); + jpeg->vfd_decoder->fops = &s5p_jpeg_fops; + jpeg->vfd_decoder->ioctl_ops = &s5p_jpeg_ioctl_ops; + jpeg->vfd_decoder->minor = -1; + jpeg->vfd_decoder->release = video_device_release; + jpeg->vfd_decoder->lock = &jpeg->lock; + jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev; + + ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); + goto dec_vdev_alloc_rollback; + } + + video_set_drvdata(jpeg->vfd_decoder, jpeg); + v4l2_info(&jpeg->v4l2_dev, + "decoder device registered as /dev/video%d\n", + jpeg->vfd_decoder->num); + + /* final statements & power management */ + platform_set_drvdata(pdev, jpeg); + + pm_runtime_enable(&pdev->dev); + + v4l2_info(&jpeg->v4l2_dev, "Samsung S5P JPEG codec\n"); + + return 0; + +dec_vdev_alloc_rollback: + video_device_release(jpeg->vfd_decoder); + +enc_vdev_register_rollback: + video_unregister_device(jpeg->vfd_encoder); + +enc_vdev_alloc_rollback: + video_device_release(jpeg->vfd_encoder); + +vb2_allocator_rollback: + vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); + +m2m_init_rollback: + v4l2_m2m_release(jpeg->m2m_dev); + +device_register_rollback: + v4l2_device_unregister(&jpeg->v4l2_dev); + +clk_get_rollback: + clk_disable(jpeg->clk); + clk_put(jpeg->clk); + +request_irq_rollback: + free_irq(jpeg->irq, jpeg); + +ioremap_rollback: + iounmap(jpeg->regs); + +mem_region_rollback: + release_resource(jpeg->ioarea); + release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea)); + +jpeg_alloc_rollback: + kfree(jpeg); + return ret; +} + +static int s5p_jpeg_remove(struct platform_device *pdev) +{ + struct s5p_jpeg *jpeg = platform_get_drvdata(pdev); + + pm_runtime_disable(jpeg->dev); + + video_unregister_device(jpeg->vfd_decoder); + video_device_release(jpeg->vfd_decoder); + video_unregister_device(jpeg->vfd_encoder); + video_device_release(jpeg->vfd_encoder); + vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); + v4l2_m2m_release(jpeg->m2m_dev); + v4l2_device_unregister(&jpeg->v4l2_dev); + + clk_disable(jpeg->clk); + clk_put(jpeg->clk); + + free_irq(jpeg->irq, jpeg); + + iounmap(jpeg->regs); + + release_resource(jpeg->ioarea); + release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea)); + kfree(jpeg); + + return 0; +} + +static int s5p_jpeg_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int s5p_jpeg_runtime_resume(struct device *dev) +{ + struct s5p_jpeg *jpeg = dev_get_drvdata(dev); + /* + * JPEG IP allows storing two Huffman tables for each component + * We fill table 0 for each component + */ + jpeg_set_hdctbl(jpeg->regs); + jpeg_set_hdctblg(jpeg->regs); + jpeg_set_hactbl(jpeg->regs); + jpeg_set_hactblg(jpeg->regs); + return 0; +} + +static const struct dev_pm_ops s5p_jpeg_pm_ops = { + .runtime_suspend = s5p_jpeg_runtime_suspend, + .runtime_resume = s5p_jpeg_runtime_resume, +}; + +static struct platform_driver s5p_jpeg_driver = { + .probe = s5p_jpeg_probe, + .remove = s5p_jpeg_remove, + .driver = { + .owner = THIS_MODULE, + .name = S5P_JPEG_M2M_NAME, + .pm = &s5p_jpeg_pm_ops, + }, +}; + +static int __init +s5p_jpeg_register(void) +{ + int ret; + + pr_info("S5P JPEG V4L2 Driver, (c) 2011 Samsung Electronics\n"); + + ret = platform_driver_register(&s5p_jpeg_driver); + + if (ret) + pr_err("%s: failed to register jpeg driver\n", __func__); + + return ret; +} + +static void __exit +s5p_jpeg_unregister(void) +{ + platform_driver_unregister(&s5p_jpeg_driver); +} + +module_init(s5p_jpeg_register); +module_exit(s5p_jpeg_unregister); + +MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>"); +MODULE_DESCRIPTION("Samsung JPEG codec driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h new file mode 100644 index 000000000000..facad6114f5e --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-core.h @@ -0,0 +1,143 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-core.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * 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. + */ + +#ifndef JPEG_CORE_H_ +#define JPEG_CORE_H_ + +#include <media/v4l2-device.h> + +#define S5P_JPEG_M2M_NAME "s5p-jpeg" + +/* JPEG compression quality setting */ +#define S5P_JPEG_COMPR_QUAL_BEST 0 +#define S5P_JPEG_COMPR_QUAL_WORST 3 + +/* JPEG RGB to YCbCr conversion matrix coefficients */ +#define S5P_JPEG_COEF11 0x4d +#define S5P_JPEG_COEF12 0x97 +#define S5P_JPEG_COEF13 0x1e +#define S5P_JPEG_COEF21 0x2c +#define S5P_JPEG_COEF22 0x57 +#define S5P_JPEG_COEF23 0x83 +#define S5P_JPEG_COEF31 0x83 +#define S5P_JPEG_COEF32 0x6e +#define S5P_JPEG_COEF33 0x13 + +/* a selection of JPEG markers */ +#define TEM 0x01 +#define SOF0 0xc0 +#define RST 0xd0 +#define SOI 0xd8 +#define EOI 0xd9 +#define DHP 0xde + +/* Flags that indicate a format can be used for capture/output */ +#define MEM2MEM_CAPTURE (1 << 0) +#define MEM2MEM_OUTPUT (1 << 1) + +/** + * struct s5p_jpeg - JPEG IP abstraction + * @lock: the mutex protecting this structure + * @v4l2_dev: v4l2 device for mem2mem mode + * @vfd_encoder: video device node for encoder mem2mem mode + * @vfd_decoder: video device node for decoder mem2mem mode + * @m2m_dev: v4l2 mem2mem device data + * @ioarea: JPEG IP memory region + * @regs: JPEG IP registers mapping + * @irq: JPEG IP irq + * @clk: JPEG IP clock + * @dev: JPEG IP struct device + * @alloc_ctx: videobuf2 memory allocator's context + */ +struct s5p_jpeg { + struct mutex lock; + + struct v4l2_device v4l2_dev; + struct video_device *vfd_encoder; + struct video_device *vfd_decoder; + struct v4l2_m2m_dev *m2m_dev; + + struct resource *ioarea; + void __iomem *regs; + unsigned int irq; + struct clk *clk; + struct device *dev; + void *alloc_ctx; +}; + +/** + * struct jpeg_fmt - driver's internal color format data + * @name: format descritpion + * @fourcc: the fourcc code, 0 if not applicable + * @depth: number of bits per pixel + * @colplanes: number of color planes (1 for packed formats) + * @h_align: horizontal alignment order (align to 2^h_align) + * @v_align: vertical alignment order (align to 2^v_align) + * @types: types of queue this format is applicable to + */ +struct s5p_jpeg_fmt { + char *name; + u32 fourcc; + int depth; + int colplanes; + int h_align; + int v_align; + u32 types; +}; + +/** + * s5p_jpeg_q_data - parameters of one queue + * @fmt: driver-specific format of this queue + * @w: image width + * @h: image height + * @size: image buffer size in bytes + */ +struct s5p_jpeg_q_data { + struct s5p_jpeg_fmt *fmt; + u32 w; + u32 h; + u32 size; +}; + +/** + * s5p_jpeg_ctx - the device context data + * @jpeg: JPEG IP device for this context + * @mode: compression (encode) operation or decompression (decode) + * @compr_quality: destination image quality in compression (encode) mode + * @m2m_ctx: mem2mem device context + * @out_q: source (output) queue information + * @cap_fmt: destination (capture) queue queue information + * @hdr_parsed: set if header has been parsed during decompression + */ +struct s5p_jpeg_ctx { + struct s5p_jpeg *jpeg; + unsigned int mode; + unsigned int compr_quality; + struct v4l2_m2m_ctx *m2m_ctx; + struct s5p_jpeg_q_data out_q; + struct s5p_jpeg_q_data cap_q; + bool hdr_parsed; +}; + +/** + * s5p_jpeg_buffer - description of memory containing input JPEG data + * @size: buffer size + * @curr: current position in the buffer + * @data: pointer to the data + */ +struct s5p_jpeg_buffer { + unsigned long size; + unsigned long curr; + unsigned long data; +}; + +#endif /* JPEG_CORE_H */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-hw.h b/drivers/media/video/s5p-jpeg/jpeg-hw.h new file mode 100644 index 000000000000..e10c744e9f23 --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-hw.h @@ -0,0 +1,353 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-hw.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * 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. + */ +#ifndef JPEG_HW_H_ +#define JPEG_HW_H_ + +#include <linux/io.h> + +#include "jpeg-hw.h" +#include "jpeg-regs.h" + +#define S5P_JPEG_MIN_WIDTH 32 +#define S5P_JPEG_MIN_HEIGHT 32 +#define S5P_JPEG_MAX_WIDTH 8192 +#define S5P_JPEG_MAX_HEIGHT 8192 +#define S5P_JPEG_ENCODE 0 +#define S5P_JPEG_DECODE 1 +#define S5P_JPEG_RAW_IN_565 0 +#define S5P_JPEG_RAW_IN_422 1 +#define S5P_JPEG_SUBSAMPLING_422 0 +#define S5P_JPEG_SUBSAMPLING_420 1 +#define S5P_JPEG_RAW_OUT_422 0 +#define S5P_JPEG_RAW_OUT_420 1 + +static inline void jpeg_reset(void __iomem *regs) +{ + unsigned long reg; + + writel(1, regs + S5P_JPG_SW_RESET); + reg = readl(regs + S5P_JPG_SW_RESET); + /* no other way but polling for when JPEG IP becomes operational */ + while (reg != 0) { + cpu_relax(); + reg = readl(regs + S5P_JPG_SW_RESET); + } +} + +static inline void jpeg_poweron(void __iomem *regs) +{ + writel(S5P_POWER_ON, regs + S5P_JPGCLKCON); +} + +static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_MOD_SEL_565; + if (mode == S5P_JPEG_RAW_IN_565) + m = S5P_MOD_SEL_565; + else if (mode == S5P_JPEG_RAW_IN_422) + m = S5P_MOD_SEL_422; + + reg = readl(regs + S5P_JPGCMOD); + reg &= ~S5P_MOD_SEL_MASK; + reg |= m; + writel(reg, regs + S5P_JPGCMOD); +} + +static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGCMOD); + if (y16) + reg |= S5P_MODE_Y16; + else + reg &= ~S5P_MODE_Y16_MASK; + writel(reg, regs + S5P_JPGCMOD); +} + +static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_PROC_MODE_DECOMPR; + if (mode == S5P_JPEG_ENCODE) + m = S5P_PROC_MODE_COMPR; + else + m = S5P_PROC_MODE_DECOMPR; + reg = readl(regs + S5P_JPGMOD); + reg &= ~S5P_PROC_MODE_MASK; + reg |= m; + writel(reg, regs + S5P_JPGMOD); +} + +static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned long mode) +{ + unsigned long reg, m; + + m = S5P_SUBSAMPLING_MODE_422; + if (mode == S5P_JPEG_SUBSAMPLING_422) + m = S5P_SUBSAMPLING_MODE_422; + else if (mode == S5P_JPEG_SUBSAMPLING_420) + m = S5P_SUBSAMPLING_MODE_420; + reg = readl(regs + S5P_JPGMOD); + reg &= ~S5P_SUBSAMPLING_MODE_MASK; + reg |= m; + writel(reg, regs + S5P_JPGMOD); +} + +static inline void jpeg_dri(void __iomem *regs, unsigned int dri) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGDRI_U); + reg &= ~0xff; + reg |= (dri >> 8) & 0xff; + writel(reg, regs + S5P_JPGDRI_U); + + reg = readl(regs + S5P_JPGDRI_L); + reg &= ~0xff; + reg |= dri & 0xff; + writel(reg, regs + S5P_JPGDRI_L); +} + +static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_QTBL); + reg &= ~S5P_QT_NUMt_MASK(t); + reg |= (n << S5P_QT_NUMt_SHIFT(t)) & S5P_QT_NUMt_MASK(t); + writel(reg, regs + S5P_JPG_QTBL); +} + +static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_HTBL); + reg &= ~S5P_HT_NUMt_AC_MASK(t); + /* this driver uses table 0 for all color components */ + reg |= (0 << S5P_HT_NUMt_AC_SHIFT(t)) & S5P_HT_NUMt_AC_MASK(t); + writel(reg, regs + S5P_JPG_HTBL); +} + +static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_HTBL); + reg &= ~S5P_HT_NUMt_DC_MASK(t); + /* this driver uses table 0 for all color components */ + reg |= (0 << S5P_HT_NUMt_DC_SHIFT(t)) & S5P_HT_NUMt_DC_MASK(t); + writel(reg, regs + S5P_JPG_HTBL); +} + +static inline void jpeg_y(void __iomem *regs, unsigned int y) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGY_U); + reg &= ~0xff; + reg |= (y >> 8) & 0xff; + writel(reg, regs + S5P_JPGY_U); + + reg = readl(regs + S5P_JPGY_L); + reg &= ~0xff; + reg |= y & 0xff; + writel(reg, regs + S5P_JPGY_L); +} + +static inline void jpeg_x(void __iomem *regs, unsigned int x) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGX_U); + reg &= ~0xff; + reg |= (x >> 8) & 0xff; + writel(reg, regs + S5P_JPGX_U); + + reg = readl(regs + S5P_JPGX_L); + reg &= ~0xff; + reg |= x & 0xff; + writel(reg, regs + S5P_JPGX_L); +} + +static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTSE); + reg &= ~S5P_RSTm_INT_EN_MASK; + if (enable) + reg |= S5P_RSTm_INT_EN; + writel(reg, regs + S5P_JPGINTSE); +} + +static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTSE); + reg &= ~S5P_DATA_NUM_INT_EN_MASK; + if (enable) + reg |= S5P_DATA_NUM_INT_EN; + writel(reg, regs + S5P_JPGINTSE); +} + +static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTSE); + reg &= ~S5P_FINAL_MCU_NUM_INT_EN_MASK; + if (enbl) + reg |= S5P_FINAL_MCU_NUM_INT_EN; + writel(reg, regs + S5P_JPGINTSE); +} + +static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_TIMER_SE); + reg |= S5P_TIMER_INT_EN; + reg &= ~S5P_TIMER_INIT_MASK; + reg |= val & S5P_TIMER_INIT_MASK; + writel(reg, regs + S5P_JPG_TIMER_SE); +} + +static inline void jpeg_timer_disable(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_TIMER_SE); + reg &= ~S5P_TIMER_INT_EN_MASK; + writel(reg, regs + S5P_JPG_TIMER_SE); +} + +static inline int jpeg_timer_stat(void __iomem *regs) +{ + return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) + >> S5P_TIMER_INT_STAT_SHIFT); +} + +static inline void jpeg_clear_timer_stat(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_TIMER_SE); + reg &= ~S5P_TIMER_INT_STAT_MASK; + writel(reg, regs + S5P_JPG_TIMER_SE); +} + +static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE); + reg &= ~S5P_ENC_STREAM_BOUND_MASK; + reg |= S5P_ENC_STREAM_INT_EN; + reg |= size & S5P_ENC_STREAM_BOUND_MASK; + writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); +} + +static inline int jpeg_enc_stream_stat(void __iomem *regs) +{ + return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) & + S5P_ENC_STREAM_INT_STAT_MASK); +} + +static inline void jpeg_clear_enc_stream_stat(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_ENC_STREAM_INTSE); + reg &= ~S5P_ENC_STREAM_INT_MASK; + writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE); +} + +static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format) +{ + unsigned long reg, f; + + f = S5P_DEC_OUT_FORMAT_422; + if (format == S5P_JPEG_RAW_OUT_422) + f = S5P_DEC_OUT_FORMAT_422; + else if (format == S5P_JPEG_RAW_OUT_420) + f = S5P_DEC_OUT_FORMAT_420; + reg = readl(regs + S5P_JPG_OUTFORM); + reg &= ~S5P_DEC_OUT_FORMAT_MASK; + reg |= f; + writel(reg, regs + S5P_JPG_OUTFORM); +} + +static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr) +{ + writel(addr, regs + S5P_JPG_JPGADR); +} + +static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr) +{ + writel(addr, regs + S5P_JPG_IMGADR); +} + +static inline void jpeg_coef(void __iomem *regs, unsigned int i, + unsigned int j, unsigned int coef) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPG_COEF(i)); + reg &= ~S5P_COEFn_MASK(j); + reg |= (coef << S5P_COEFn_SHIFT(j)) & S5P_COEFn_MASK(j); + writel(reg, regs + S5P_JPG_COEF(i)); +} + +static inline void jpeg_start(void __iomem *regs) +{ + writel(1, regs + S5P_JSTART); +} + +static inline int jpeg_result_stat_ok(void __iomem *regs) +{ + return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK) + >> S5P_RESULT_STAT_SHIFT); +} + +static inline int jpeg_stream_stat_ok(void __iomem *regs) +{ + return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK) + >> S5P_STREAM_STAT_SHIFT); +} + +static inline void jpeg_clear_int(void __iomem *regs) +{ + unsigned long reg; + + reg = readl(regs + S5P_JPGINTST); + writel(S5P_INT_RELEASE, regs + S5P_JPGCOM); + reg = readl(regs + S5P_JPGOPR); +} + +static inline unsigned int jpeg_compressed_size(void __iomem *regs) +{ + unsigned long jpeg_size = 0; + + jpeg_size |= (readl(regs + S5P_JPGCNT_U) & 0xff) << 16; + jpeg_size |= (readl(regs + S5P_JPGCNT_M) & 0xff) << 8; + jpeg_size |= (readl(regs + S5P_JPGCNT_L) & 0xff); + + return (unsigned int)jpeg_size; +} + +#endif /* JPEG_HW_H_ */ diff --git a/drivers/media/video/s5p-jpeg/jpeg-regs.h b/drivers/media/video/s5p-jpeg/jpeg-regs.h new file mode 100644 index 000000000000..91f4dd5f86dd --- /dev/null +++ b/drivers/media/video/s5p-jpeg/jpeg-regs.h @@ -0,0 +1,170 @@ +/* linux/drivers/media/video/s5p-jpeg/jpeg-regs.h + * + * Register definition file for Samsung JPEG codec driver + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * 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. + */ + +#ifndef JPEG_REGS_H_ +#define JPEG_REGS_H_ + +/* JPEG mode register */ +#define S5P_JPGMOD 0x00 +#define S5P_PROC_MODE_MASK (0x1 << 3) +#define S5P_PROC_MODE_DECOMPR (0x1 << 3) +#define S5P_PROC_MODE_COMPR (0x0 << 3) +#define S5P_SUBSAMPLING_MODE_MASK 0x7 +#define S5P_SUBSAMPLING_MODE_444 (0x0 << 0) +#define S5P_SUBSAMPLING_MODE_422 (0x1 << 0) +#define S5P_SUBSAMPLING_MODE_420 (0x2 << 0) +#define S5P_SUBSAMPLING_MODE_GRAY (0x3 << 0) + +/* JPEG operation status register */ +#define S5P_JPGOPR 0x04 + +/* Quantization tables*/ +#define S5P_JPG_QTBL 0x08 +#define S5P_QT_NUMt_SHIFT(t) (((t) - 1) << 1) +#define S5P_QT_NUMt_MASK(t) (0x3 << S5P_QT_NUMt_SHIFT(t)) + +/* Huffman tables */ +#define S5P_JPG_HTBL 0x0c +#define S5P_HT_NUMt_AC_SHIFT(t) (((t) << 1) - 1) +#define S5P_HT_NUMt_AC_MASK(t) (0x1 << S5P_HT_NUMt_AC_SHIFT(t)) + +#define S5P_HT_NUMt_DC_SHIFT(t) (((t) - 1) << 1) +#define S5P_HT_NUMt_DC_MASK(t) (0x1 << S5P_HT_NUMt_DC_SHIFT(t)) + +/* JPEG restart interval register upper byte */ +#define S5P_JPGDRI_U 0x10 + +/* JPEG restart interval register lower byte */ +#define S5P_JPGDRI_L 0x14 + +/* JPEG vertical resolution register upper byte */ +#define S5P_JPGY_U 0x18 + +/* JPEG vertical resolution register lower byte */ +#define S5P_JPGY_L 0x1c + +/* JPEG horizontal resolution register upper byte */ +#define S5P_JPGX_U 0x20 + +/* JPEG horizontal resolution register lower byte */ +#define S5P_JPGX_L 0x24 + +/* JPEG byte count register upper byte */ +#define S5P_JPGCNT_U 0x28 + +/* JPEG byte count register middle byte */ +#define S5P_JPGCNT_M 0x2c + +/* JPEG byte count register lower byte */ +#define S5P_JPGCNT_L 0x30 + +/* JPEG interrupt setting register */ +#define S5P_JPGINTSE 0x34 +#define S5P_RSTm_INT_EN_MASK (0x1 << 7) +#define S5P_RSTm_INT_EN (0x1 << 7) +#define S5P_DATA_NUM_INT_EN_MASK (0x1 << 6) +#define S5P_DATA_NUM_INT_EN (0x1 << 6) +#define S5P_FINAL_MCU_NUM_INT_EN_MASK (0x1 << 5) +#define S5P_FINAL_MCU_NUM_INT_EN (0x1 << 5) + +/* JPEG interrupt status register */ +#define S5P_JPGINTST 0x38 +#define S5P_RESULT_STAT_SHIFT 6 +#define S5P_RESULT_STAT_MASK (0x1 << S5P_RESULT_STAT_SHIFT) +#define S5P_STREAM_STAT_SHIFT 5 +#define S5P_STREAM_STAT_MASK (0x1 << S5P_STREAM_STAT_SHIFT) + +/* JPEG command register */ +#define S5P_JPGCOM 0x4c +#define S5P_INT_RELEASE (0x1 << 2) + +/* Raw image data r/w address register */ +#define S5P_JPG_IMGADR 0x50 + +/* JPEG file r/w address register */ +#define S5P_JPG_JPGADR 0x58 + +/* Coefficient for RGB-to-YCbCr converter register */ +#define S5P_JPG_COEF(n) (0x5c + (((n) - 1) << 2)) +#define S5P_COEFn_SHIFT(j) ((3 - (j)) << 3) +#define S5P_COEFn_MASK(j) (0xff << S5P_COEFn_SHIFT(j)) + +/* JPEG color mode register */ +#define S5P_JPGCMOD 0x68 +#define S5P_MOD_SEL_MASK (0x7 << 5) +#define S5P_MOD_SEL_422 (0x1 << 5) +#define S5P_MOD_SEL_565 (0x2 << 5) +#define S5P_MODE_Y16_MASK (0x1 << 1) +#define S5P_MODE_Y16 (0x1 << 1) + +/* JPEG clock control register */ +#define S5P_JPGCLKCON 0x6c +#define S5P_CLK_DOWN_READY (0x1 << 1) +#define S5P_POWER_ON (0x1 << 0) + +/* JPEG start register */ +#define S5P_JSTART 0x70 + +/* JPEG SW reset register */ +#define S5P_JPG_SW_RESET 0x78 + +/* JPEG timer setting register */ +#define S5P_JPG_TIMER_SE 0x7c +#define S5P_TIMER_INT_EN_MASK (0x1 << 31) +#define S5P_TIMER_INT_EN (0x1 << 31) +#define S5P_TIMER_INIT_MASK 0x7fffffff + +/* JPEG timer status register */ +#define S5P_JPG_TIMER_ST 0x80 +#define S5P_TIMER_INT_STAT_SHIFT 31 +#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT) +#define S5P_TIMER_CNT_SHIFT 0 +#define S5P_TIMER_CNT_MASK 0x7fffffff + +/* JPEG decompression output format register */ +#define S5P_JPG_OUTFORM 0x88 +#define S5P_DEC_OUT_FORMAT_MASK (0x1 << 0) +#define S5P_DEC_OUT_FORMAT_422 (0x0 << 0) +#define S5P_DEC_OUT_FORMAT_420 (0x1 << 0) + +/* JPEG version register */ +#define S5P_JPG_VERSION 0x8c + +/* JPEG compressed stream size interrupt setting register */ +#define S5P_JPG_ENC_STREAM_INTSE 0x98 +#define S5P_ENC_STREAM_INT_MASK (0x1 << 24) +#define S5P_ENC_STREAM_INT_EN (0x1 << 24) +#define S5P_ENC_STREAM_BOUND_MASK 0xffffff + +/* JPEG compressed stream size interrupt status register */ +#define S5P_JPG_ENC_STREAM_INTST 0x9c +#define S5P_ENC_STREAM_INT_STAT_MASK 0x1 + +/* JPEG quantizer table register */ +#define S5P_JPG_QTBL_CONTENT(n) (0x400 + (n) * 0x100) + +/* JPEG DC Huffman table register */ +#define S5P_JPG_HDCTBL(n) (0x800 + (n) * 0x400) + +/* JPEG DC Huffman table register */ +#define S5P_JPG_HDCTBLG(n) (0x840 + (n) * 0x400) + +/* JPEG AC Huffman table register */ +#define S5P_JPG_HACTBL(n) (0x880 + (n) * 0x400) + +/* JPEG AC Huffman table register */ +#define S5P_JPG_HACTBLG(n) (0x8c0 + (n) * 0x400) + +#endif /* JPEG_REGS_H_ */ + diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c index 8be8b54eb749..e43e128baf5f 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc.c @@ -1245,27 +1245,7 @@ static struct platform_driver s5p_mfc_driver = { }, }; -static char banner[] __initdata = - "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n"; - -static int __init s5p_mfc_init(void) -{ - int ret; - - pr_info("%s", banner); - ret = platform_driver_register(&s5p_mfc_driver); - if (ret) - pr_err("Platform device registration failed.\n"); - return ret; -} - -static void __exit s5p_mfc_exit(void) -{ - platform_driver_unregister(&s5p_mfc_driver); -} - -module_init(s5p_mfc_init); -module_exit(s5p_mfc_exit); +module_platform_driver(s5p_mfc_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c index 0279e6e89feb..8b41a0410ab1 100644 --- a/drivers/media/video/s5p-tv/hdmi_drv.c +++ b/drivers/media/video/s5p-tv/hdmi_drv.c @@ -838,8 +838,8 @@ static int hdmi_resources_init(struct hdmi_device *hdev) dev_err(dev, "failed to get clock 'hdmiphy'\n"); goto fail; } - res->regul_bulk = kzalloc(ARRAY_SIZE(supply) * - sizeof res->regul_bulk[0], GFP_KERNEL); + res->regul_bulk = kcalloc(ARRAY_SIZE(supply), + sizeof(res->regul_bulk[0]), GFP_KERNEL); if (!res->regul_bulk) { dev_err(dev, "failed to get memory for regulators\n"); goto fail; @@ -1016,28 +1016,4 @@ static struct platform_driver hdmi_driver __refdata = { } }; -/* D R I V E R I N I T I A L I Z A T I O N */ - -static int __init hdmi_init(void) -{ - int ret; - static const char banner[] __initdata = KERN_INFO \ - "Samsung HDMI output driver, " - "(c) 2010-2011 Samsung Electronics Co., Ltd.\n"; - printk(banner); - - ret = platform_driver_register(&hdmi_driver); - if (ret) - printk(KERN_ERR "HDMI platform driver register failed\n"); - - return ret; -} -module_init(hdmi_init); - -static void __exit hdmi_exit(void) -{ - platform_driver_unregister(&hdmi_driver); -} -module_exit(hdmi_exit); - - +module_platform_driver(hdmi_driver); diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h index 51ad59b30358..1597078c4a50 100644 --- a/drivers/media/video/s5p-tv/mixer.h +++ b/drivers/media/video/s5p-tv/mixer.h @@ -86,6 +86,17 @@ struct mxr_crop { unsigned int field; }; +/** stages of geometry operations */ +enum mxr_geometry_stage { + MXR_GEOMETRY_SINK, + MXR_GEOMETRY_COMPOSE, + MXR_GEOMETRY_CROP, + MXR_GEOMETRY_SOURCE, +}; + +/* flag indicating that offset should be 0 */ +#define MXR_NO_OFFSET 0x80000000 + /** description of transformation from source to destination image */ struct mxr_geometry { /** cropping for source image */ @@ -133,7 +144,8 @@ struct mxr_layer_ops { /** streaming stop/start */ void (*stream_set)(struct mxr_layer *, int); /** adjusting geometry */ - void (*fix_geometry)(struct mxr_layer *); + void (*fix_geometry)(struct mxr_layer *, + enum mxr_geometry_stage, unsigned long); }; /** layer instance, a single window and content displayed on output */ diff --git a/drivers/media/video/s5p-tv/mixer_grp_layer.c b/drivers/media/video/s5p-tv/mixer_grp_layer.c index de8270c2b6e7..b93a21f5aa13 100644 --- a/drivers/media/video/s5p-tv/mixer_grp_layer.c +++ b/drivers/media/video/s5p-tv/mixer_grp_layer.c @@ -101,47 +101,132 @@ static void mxr_graph_format_set(struct mxr_layer *layer) layer->fmt, &layer->geo); } -static void mxr_graph_fix_geometry(struct mxr_layer *layer) +static inline unsigned int closest(unsigned int x, unsigned int a, + unsigned int b, unsigned long flags) +{ + unsigned int mid = (a + b) / 2; + + /* choosing closest value with constraints according to table: + * -------------+-----+-----+-----+-------+ + * flags | 0 | LE | GE | LE|GE | + * -------------+-----+-----+-----+-------+ + * x <= a | a | a | a | a | + * a < x <= mid | a | a | b | a | + * mid < x < b | b | a | b | b | + * b <= x | b | b | b | b | + * -------------+-----+-----+-----+-------+ + */ + + /* remove all non-constraint flags */ + flags &= V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE; + + if (x <= a) + return a; + if (x >= b) + return b; + if (flags == V4L2_SEL_FLAG_LE) + return a; + if (flags == V4L2_SEL_FLAG_GE) + return b; + if (x <= mid) + return a; + return b; +} + +static inline unsigned int do_center(unsigned int center, + unsigned int size, unsigned int upper, unsigned int flags) +{ + unsigned int lower; + + if (flags & MXR_NO_OFFSET) + return 0; + + lower = center - min(center, size / 2); + return min(lower, upper - size); +} + +static void mxr_graph_fix_geometry(struct mxr_layer *layer, + enum mxr_geometry_stage stage, unsigned long flags) { struct mxr_geometry *geo = &layer->geo; + struct mxr_crop *src = &geo->src; + struct mxr_crop *dst = &geo->dst; + unsigned int x_center, y_center; - /* limit to boundary size */ - geo->src.full_width = clamp_val(geo->src.full_width, 1, 32767); - geo->src.full_height = clamp_val(geo->src.full_height, 1, 2047); - geo->src.width = clamp_val(geo->src.width, 1, geo->src.full_width); - geo->src.width = min(geo->src.width, 2047U); - /* not possible to crop of Y axis */ - geo->src.y_offset = min(geo->src.y_offset, geo->src.full_height - 1); - geo->src.height = geo->src.full_height - geo->src.y_offset; - /* limitting offset */ - geo->src.x_offset = min(geo->src.x_offset, - geo->src.full_width - geo->src.width); - - /* setting position in output */ - geo->dst.width = min(geo->dst.width, geo->dst.full_width); - geo->dst.height = min(geo->dst.height, geo->dst.full_height); - - /* Mixer supports only 1x and 2x scaling */ - if (geo->dst.width >= 2 * geo->src.width) { - geo->x_ratio = 1; - geo->dst.width = 2 * geo->src.width; - } else { - geo->x_ratio = 0; - geo->dst.width = geo->src.width; - } + switch (stage) { - if (geo->dst.height >= 2 * geo->src.height) { - geo->y_ratio = 1; - geo->dst.height = 2 * geo->src.height; - } else { - geo->y_ratio = 0; - geo->dst.height = geo->src.height; - } + case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ + flags = 0; + /* fall through */ + + case MXR_GEOMETRY_COMPOSE: + /* remember center of the area */ + x_center = dst->x_offset + dst->width / 2; + y_center = dst->y_offset + dst->height / 2; + /* round up/down to 2 multiple depending on flags */ + if (flags & V4L2_SEL_FLAG_LE) { + dst->width = round_down(dst->width, 2); + dst->height = round_down(dst->height, 2); + } else { + dst->width = round_up(dst->width, 2); + dst->height = round_up(dst->height, 2); + } + /* assure that compose rect is inside display area */ + dst->width = min(dst->width, dst->full_width); + dst->height = min(dst->height, dst->full_height); + + /* ensure that compose is reachable using 2x scaling */ + dst->width = min(dst->width, 2 * src->full_width); + dst->height = min(dst->height, 2 * src->full_height); + + /* setup offsets */ + dst->x_offset = do_center(x_center, dst->width, + dst->full_width, flags); + dst->y_offset = do_center(y_center, dst->height, + dst->full_height, flags); + flags = 0; + /* fall through */ - geo->dst.x_offset = min(geo->dst.x_offset, - geo->dst.full_width - geo->dst.width); - geo->dst.y_offset = min(geo->dst.y_offset, - geo->dst.full_height - geo->dst.height); + case MXR_GEOMETRY_CROP: + /* remember center of the area */ + x_center = src->x_offset + src->width / 2; + y_center = src->y_offset + src->height / 2; + /* ensure that cropping area lies inside the buffer */ + if (src->full_width < dst->width) + src->width = dst->width / 2; + else + src->width = closest(src->width, dst->width / 2, + dst->width, flags); + + if (src->width == dst->width) + geo->x_ratio = 0; + else + geo->x_ratio = 1; + + if (src->full_height < dst->height) + src->height = dst->height / 2; + else + src->height = closest(src->height, dst->height / 2, + dst->height, flags); + + if (src->height == dst->height) + geo->y_ratio = 0; + else + geo->y_ratio = 1; + + /* setup offsets */ + src->x_offset = do_center(x_center, src->width, + src->full_width, flags); + src->y_offset = do_center(y_center, src->height, + src->full_height, flags); + flags = 0; + /* fall through */ + case MXR_GEOMETRY_SOURCE: + src->full_width = clamp_val(src->full_width, + src->width + src->x_offset, 32767); + src->full_height = clamp_val(src->full_height, + src->height + src->y_offset, 2047); + }; } /* PUBLIC API */ diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index b47d0c06ecf5..7884baeff76a 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -170,18 +170,22 @@ static int mxr_querycap(struct file *file, void *priv, return 0; } -/* Geometry handling */ -static void mxr_layer_geo_fix(struct mxr_layer *layer) +static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo) { - struct mxr_device *mdev = layer->mdev; - struct v4l2_mbus_framefmt mbus_fmt; - - /* TODO: add some dirty flag to avoid unnecessary adjustments */ - mxr_get_mbus_fmt(mdev, &mbus_fmt); - layer->geo.dst.full_width = mbus_fmt.width; - layer->geo.dst.full_height = mbus_fmt.height; - layer->geo.dst.field = mbus_fmt.field; - layer->ops.fix_geometry(layer); + mxr_dbg(mdev, "src.full_size = (%u, %u)\n", + geo->src.full_width, geo->src.full_height); + mxr_dbg(mdev, "src.size = (%u, %u)\n", + geo->src.width, geo->src.height); + mxr_dbg(mdev, "src.offset = (%u, %u)\n", + geo->src.x_offset, geo->src.y_offset); + mxr_dbg(mdev, "dst.full_size = (%u, %u)\n", + geo->dst.full_width, geo->dst.full_height); + mxr_dbg(mdev, "dst.size = (%u, %u)\n", + geo->dst.width, geo->dst.height); + mxr_dbg(mdev, "dst.offset = (%u, %u)\n", + geo->dst.x_offset, geo->dst.y_offset); + mxr_dbg(mdev, "ratio = (%u, %u)\n", + geo->x_ratio, geo->y_ratio); } static void mxr_layer_default_geo(struct mxr_layer *layer) @@ -204,27 +208,29 @@ static void mxr_layer_default_geo(struct mxr_layer *layer) layer->geo.src.width = layer->geo.src.full_width; layer->geo.src.height = layer->geo.src.full_height; - layer->ops.fix_geometry(layer); + mxr_geometry_dump(mdev, &layer->geo); + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); + mxr_geometry_dump(mdev, &layer->geo); } -static void mxr_geometry_dump(struct mxr_device *mdev, struct mxr_geometry *geo) +static void mxr_layer_update_output(struct mxr_layer *layer) { - mxr_dbg(mdev, "src.full_size = (%u, %u)\n", - geo->src.full_width, geo->src.full_height); - mxr_dbg(mdev, "src.size = (%u, %u)\n", - geo->src.width, geo->src.height); - mxr_dbg(mdev, "src.offset = (%u, %u)\n", - geo->src.x_offset, geo->src.y_offset); - mxr_dbg(mdev, "dst.full_size = (%u, %u)\n", - geo->dst.full_width, geo->dst.full_height); - mxr_dbg(mdev, "dst.size = (%u, %u)\n", - geo->dst.width, geo->dst.height); - mxr_dbg(mdev, "dst.offset = (%u, %u)\n", - geo->dst.x_offset, geo->dst.y_offset); - mxr_dbg(mdev, "ratio = (%u, %u)\n", - geo->x_ratio, geo->y_ratio); -} + struct mxr_device *mdev = layer->mdev; + struct v4l2_mbus_framefmt mbus_fmt; + + mxr_get_mbus_fmt(mdev, &mbus_fmt); + /* checking if update is needed */ + if (layer->geo.dst.full_width == mbus_fmt.width && + layer->geo.dst.full_height == mbus_fmt.width) + return; + layer->geo.dst.full_width = mbus_fmt.width; + layer->geo.dst.full_height = mbus_fmt.height; + layer->geo.dst.field = mbus_fmt.field; + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SINK, 0); + + mxr_geometry_dump(mdev, &layer->geo); +} static const struct mxr_format *find_format_by_fourcc( struct mxr_layer *layer, unsigned long fourcc); @@ -249,37 +255,6 @@ static int mxr_enum_fmt(struct file *file, void *priv, return 0; } -static int mxr_s_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct mxr_layer *layer = video_drvdata(file); - const struct mxr_format *fmt; - struct v4l2_pix_format_mplane *pix; - struct mxr_device *mdev = layer->mdev; - struct mxr_geometry *geo = &layer->geo; - - mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__); - - pix = &f->fmt.pix_mp; - fmt = find_format_by_fourcc(layer, pix->pixelformat); - if (fmt == NULL) { - mxr_warn(mdev, "not recognized fourcc: %08x\n", - pix->pixelformat); - return -EINVAL; - } - layer->fmt = fmt; - geo->src.full_width = pix->width; - geo->src.width = pix->width; - geo->src.full_height = pix->height; - geo->src.height = pix->height; - /* assure consistency of geometry */ - mxr_layer_geo_fix(layer); - mxr_dbg(mdev, "width=%u height=%u span=%u\n", - geo->src.width, geo->src.height, geo->src.full_width); - - return 0; -} - static unsigned int divup(unsigned int divident, unsigned int divisor) { return (divident + divisor - 1) / divisor; @@ -299,6 +274,10 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes, { int i; + /* checking if nothing to fill */ + if (!planes) + return; + memset(planes, 0, sizeof(*planes) * fmt->num_subframes); for (i = 0; i < fmt->num_planes; ++i) { struct v4l2_plane_pix_format *plane = planes @@ -332,73 +311,194 @@ static int mxr_g_fmt(struct file *file, void *priv, return 0; } -static inline struct mxr_crop *choose_crop_by_type(struct mxr_geometry *geo, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return &geo->dst; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - return &geo->src; - default: - return NULL; - } -} - -static int mxr_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int mxr_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) { struct mxr_layer *layer = video_drvdata(file); - struct mxr_crop *crop; + const struct mxr_format *fmt; + struct v4l2_pix_format_mplane *pix; + struct mxr_device *mdev = layer->mdev; + struct mxr_geometry *geo = &layer->geo; - mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); - crop = choose_crop_by_type(&layer->geo, a->type); - if (crop == NULL) + mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__); + + pix = &f->fmt.pix_mp; + fmt = find_format_by_fourcc(layer, pix->pixelformat); + if (fmt == NULL) { + mxr_warn(mdev, "not recognized fourcc: %08x\n", + pix->pixelformat); return -EINVAL; - mxr_layer_geo_fix(layer); - a->c.left = crop->x_offset; - a->c.top = crop->y_offset; - a->c.width = crop->width; - a->c.height = crop->height; + } + layer->fmt = fmt; + /* set source size to highest accepted value */ + geo->src.full_width = max(geo->dst.full_width, pix->width); + geo->src.full_height = max(geo->dst.full_height, pix->height); + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); + mxr_geometry_dump(mdev, &layer->geo); + /* set cropping to total visible screen */ + geo->src.width = pix->width; + geo->src.height = pix->height; + geo->src.x_offset = 0; + geo->src.y_offset = 0; + /* assure consistency of geometry */ + layer->ops.fix_geometry(layer, MXR_GEOMETRY_CROP, MXR_NO_OFFSET); + mxr_geometry_dump(mdev, &layer->geo); + /* set full size to lowest possible value */ + geo->src.full_width = 0; + geo->src.full_height = 0; + layer->ops.fix_geometry(layer, MXR_GEOMETRY_SOURCE, 0); + mxr_geometry_dump(mdev, &layer->geo); + + /* returning results */ + mxr_g_fmt(file, priv, f); + return 0; } -static int mxr_s_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int mxr_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) { struct mxr_layer *layer = video_drvdata(file); - struct mxr_crop *crop; + struct mxr_geometry *geo = &layer->geo; mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); - crop = choose_crop_by_type(&layer->geo, a->type); - if (crop == NULL) + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP_ACTIVE: + s->r.left = geo->src.x_offset; + s->r.top = geo->src.y_offset; + s->r.width = geo->src.width; + s->r.height = geo->src.height; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = geo->src.full_width; + s->r.height = geo->src.full_height; + break; + case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE_PADDED: + s->r.left = geo->dst.x_offset; + s->r.top = geo->dst.y_offset; + s->r.width = geo->dst.width; + s->r.height = geo->dst.height; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = geo->dst.full_width; + s->r.height = geo->dst.full_height; + break; + default: return -EINVAL; - crop->x_offset = a->c.left; - crop->y_offset = a->c.top; - crop->width = a->c.width; - crop->height = a->c.height; - mxr_layer_geo_fix(layer); + } + return 0; } -static int mxr_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a) +/* returns 1 if rectangle 'a' is inside 'b' */ +static int mxr_is_rect_inside(struct v4l2_rect *a, struct v4l2_rect *b) +{ + if (a->left < b->left) + return 0; + if (a->top < b->top) + return 0; + if (a->left + a->width > b->left + b->width) + return 0; + if (a->top + a->height > b->top + b->height) + return 0; + return 1; +} + +static int mxr_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) { struct mxr_layer *layer = video_drvdata(file); - struct mxr_crop *crop; + struct mxr_geometry *geo = &layer->geo; + struct mxr_crop *target = NULL; + enum mxr_geometry_stage stage; + struct mxr_geometry tmp; + struct v4l2_rect res; - mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); - crop = choose_crop_by_type(&layer->geo, a->type); - if (crop == NULL) + memset(&res, 0, sizeof res); + + mxr_dbg(layer->mdev, "%s: rect: %dx%d@%d,%d\n", __func__, + s->r.width, s->r.height, s->r.left, s->r.top); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; - mxr_layer_geo_fix(layer); - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = crop->full_width; - a->bounds.top = crop->full_height; - a->defrect = a->bounds; - /* setting pixel aspect to 1/1 */ - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; + + switch (s->target) { + /* ignore read-only targets */ + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + res.width = geo->src.full_width; + res.height = geo->src.full_height; + break; + + /* ignore read-only targets */ + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + res.width = geo->dst.full_width; + res.height = geo->dst.full_height; + break; + + case V4L2_SEL_TGT_CROP_ACTIVE: + target = &geo->src; + stage = MXR_GEOMETRY_CROP; + break; + case V4L2_SEL_TGT_COMPOSE_ACTIVE: + case V4L2_SEL_TGT_COMPOSE_PADDED: + target = &geo->dst; + stage = MXR_GEOMETRY_COMPOSE; + break; + default: + return -EINVAL; + } + /* apply change and update geometry if needed */ + if (target) { + /* backup current geometry if setup fails */ + memcpy(&tmp, geo, sizeof tmp); + + /* apply requested selection */ + target->x_offset = s->r.left; + target->y_offset = s->r.top; + target->width = s->r.width; + target->height = s->r.height; + + layer->ops.fix_geometry(layer, stage, s->flags); + + /* retrieve update selection rectangle */ + res.left = target->x_offset; + res.top = target->y_offset; + res.width = target->width; + res.height = target->height; + + mxr_geometry_dump(layer->mdev, &layer->geo); + } + + /* checking if the rectangle satisfies constraints */ + if ((s->flags & V4L2_SEL_FLAG_LE) && !mxr_is_rect_inside(&res, &s->r)) + goto fail; + if ((s->flags & V4L2_SEL_FLAG_GE) && !mxr_is_rect_inside(&s->r, &res)) + goto fail; + + /* return result rectangle */ + s->r = res; + return 0; +fail: + /* restore old geometry, which is not touched if target is NULL */ + if (target) + memcpy(geo, &tmp, sizeof tmp); + return -ERANGE; } static int mxr_enum_dv_presets(struct file *file, void *fh, @@ -438,6 +538,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh, mutex_unlock(&mdev->mutex); + mxr_layer_update_output(layer); + /* any failure should return EINVAL according to V4L2 doc */ return ret ? -EINVAL : 0; } @@ -478,6 +580,8 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) mutex_unlock(&mdev->mutex); + mxr_layer_update_output(layer); + return ret ? -EINVAL : 0; } @@ -526,25 +630,27 @@ static int mxr_s_output(struct file *file, void *fh, unsigned int i) struct video_device *vfd = video_devdata(file); struct mxr_layer *layer = video_drvdata(file); struct mxr_device *mdev = layer->mdev; - int ret = 0; if (i >= mdev->output_cnt || mdev->output[i] == NULL) return -EINVAL; mutex_lock(&mdev->mutex); if (mdev->n_output > 0) { - ret = -EBUSY; - goto done; + mutex_unlock(&mdev->mutex); + return -EBUSY; } mdev->current_output = i; vfd->tvnorms = 0; v4l2_subdev_call(to_outsd(mdev), video, g_tvnorms_output, &vfd->tvnorms); + mutex_unlock(&mdev->mutex); + + /* update layers geometry */ + mxr_layer_update_output(layer); + mxr_dbg(mdev, "tvnorms = %08llx\n", vfd->tvnorms); -done: - mutex_unlock(&mdev->mutex); - return ret; + return 0; } static int mxr_g_output(struct file *file, void *fh, unsigned int *p) @@ -633,10 +739,9 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = { .vidioc_enum_output = mxr_enum_output, .vidioc_s_output = mxr_s_output, .vidioc_g_output = mxr_g_output, - /* Crop ioctls */ - .vidioc_g_crop = mxr_g_crop, - .vidioc_s_crop = mxr_s_crop, - .vidioc_cropcap = mxr_cropcap, + /* selection ioctls */ + .vidioc_g_selection = mxr_g_selection, + .vidioc_s_selection = mxr_s_selection, }; static int mxr_video_open(struct file *file) @@ -805,10 +910,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* block any changes in output configuration */ mxr_output_get(mdev); - /* update layers geometry */ - mxr_layer_geo_fix(layer); - mxr_geometry_dump(mdev, &layer->geo); - + mxr_layer_update_output(layer); layer->ops.format_set(layer); /* enabling layer in hardware */ spin_lock_irqsave(&layer->enq_slock, flags); diff --git a/drivers/media/video/s5p-tv/mixer_vp_layer.c b/drivers/media/video/s5p-tv/mixer_vp_layer.c index f3bb2e34cb51..3d13a636877b 100644 --- a/drivers/media/video/s5p-tv/mixer_vp_layer.c +++ b/drivers/media/video/s5p-tv/mixer_vp_layer.c @@ -127,47 +127,77 @@ static void mxr_vp_format_set(struct mxr_layer *layer) mxr_reg_vp_format(layer->mdev, layer->fmt, &layer->geo); } -static void mxr_vp_fix_geometry(struct mxr_layer *layer) +static inline unsigned int do_center(unsigned int center, + unsigned int size, unsigned int upper, unsigned int flags) { - struct mxr_geometry *geo = &layer->geo; + unsigned int lower; + + if (flags & MXR_NO_OFFSET) + return 0; + + lower = center - min(center, size / 2); + return min(lower, upper - size); +} - /* align horizontal size to 8 pixels */ - geo->src.full_width = ALIGN(geo->src.full_width, 8); - /* limit to boundary size */ - geo->src.full_width = clamp_val(geo->src.full_width, 8, 8192); - geo->src.full_height = clamp_val(geo->src.full_height, 1, 8192); - geo->src.width = clamp_val(geo->src.width, 32, geo->src.full_width); - geo->src.width = min(geo->src.width, 2047U); - geo->src.height = clamp_val(geo->src.height, 4, geo->src.full_height); - geo->src.height = min(geo->src.height, 2047U); - - /* setting size of output window */ - geo->dst.width = clamp_val(geo->dst.width, 8, geo->dst.full_width); - geo->dst.height = clamp_val(geo->dst.height, 1, geo->dst.full_height); - - /* ensure that scaling is in range 1/4x to 16x */ - if (geo->src.width >= 4 * geo->dst.width) - geo->src.width = 4 * geo->dst.width; - if (geo->dst.width >= 16 * geo->src.width) - geo->dst.width = 16 * geo->src.width; - if (geo->src.height >= 4 * geo->dst.height) - geo->src.height = 4 * geo->dst.height; - if (geo->dst.height >= 16 * geo->src.height) - geo->dst.height = 16 * geo->src.height; - - /* setting scaling ratio */ - geo->x_ratio = (geo->src.width << 16) / geo->dst.width; - geo->y_ratio = (geo->src.height << 16) / geo->dst.height; - - /* adjust offsets */ - geo->src.x_offset = min(geo->src.x_offset, - geo->src.full_width - geo->src.width); - geo->src.y_offset = min(geo->src.y_offset, - geo->src.full_height - geo->src.height); - geo->dst.x_offset = min(geo->dst.x_offset, - geo->dst.full_width - geo->dst.width); - geo->dst.y_offset = min(geo->dst.y_offset, - geo->dst.full_height - geo->dst.height); +static void mxr_vp_fix_geometry(struct mxr_layer *layer, + enum mxr_geometry_stage stage, unsigned long flags) +{ + struct mxr_geometry *geo = &layer->geo; + struct mxr_crop *src = &geo->src; + struct mxr_crop *dst = &geo->dst; + unsigned long x_center, y_center; + + switch (stage) { + + case MXR_GEOMETRY_SINK: /* nothing to be fixed here */ + case MXR_GEOMETRY_COMPOSE: + /* remember center of the area */ + x_center = dst->x_offset + dst->width / 2; + y_center = dst->y_offset + dst->height / 2; + + /* ensure that compose is reachable using 16x scaling */ + dst->width = clamp(dst->width, 8U, 16 * src->full_width); + dst->height = clamp(dst->height, 1U, 16 * src->full_height); + + /* setup offsets */ + dst->x_offset = do_center(x_center, dst->width, + dst->full_width, flags); + dst->y_offset = do_center(y_center, dst->height, + dst->full_height, flags); + flags = 0; /* remove possible MXR_NO_OFFSET flag */ + /* fall through */ + case MXR_GEOMETRY_CROP: + /* remember center of the area */ + x_center = src->x_offset + src->width / 2; + y_center = src->y_offset + src->height / 2; + + /* ensure scaling is between 0.25x .. 16x */ + src->width = clamp(src->width, round_up(dst->width / 16, 4), + dst->width * 4); + src->height = clamp(src->height, round_up(dst->height / 16, 4), + dst->height * 4); + + /* hardware limits */ + src->width = clamp(src->width, 32U, 2047U); + src->height = clamp(src->height, 4U, 2047U); + + /* setup offsets */ + src->x_offset = do_center(x_center, src->width, + src->full_width, flags); + src->y_offset = do_center(y_center, src->height, + src->full_height, flags); + + /* setting scaling ratio */ + geo->x_ratio = (src->width << 16) / dst->width; + geo->y_ratio = (src->height << 16) / dst->height; + /* fall through */ + + case MXR_GEOMETRY_SOURCE: + src->full_width = clamp(src->full_width, + ALIGN(src->width + src->x_offset, 8), 8192U); + src->full_height = clamp(src->full_height, + src->height + src->y_offset, 8192U); + }; } /* PUBLIC API */ diff --git a/drivers/media/video/s5p-tv/sdo_drv.c b/drivers/media/video/s5p-tv/sdo_drv.c index 8cec67ef48c9..059e7749ce95 100644 --- a/drivers/media/video/s5p-tv/sdo_drv.c +++ b/drivers/media/video/s5p-tv/sdo_drv.c @@ -457,24 +457,4 @@ static struct platform_driver sdo_driver __refdata = { } }; -static int __init sdo_init(void) -{ - int ret; - static const char banner[] __initdata = KERN_INFO \ - "Samsung Standard Definition Output (SDO) driver, " - "(c) 2010-2011 Samsung Electronics Co., Ltd.\n"; - printk(banner); - - ret = platform_driver_register(&sdo_driver); - if (ret) - printk(KERN_ERR "SDO platform driver register failed\n"); - - return ret; -} -module_init(sdo_init); - -static void __exit sdo_exit(void) -{ - platform_driver_unregister(&sdo_driver); -} -module_exit(sdo_exit); +module_platform_driver(sdo_driver); diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 5cfdbc78b918..0ef5484696b6 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -57,7 +57,7 @@ MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " "Hans Verkuil, Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 0f9fb99adeb4..065d0f6be4a0 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -5691,6 +5691,27 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_SENSORAY811_911] = { + .name = "Sensoray 811/911", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + }, { + .name = name_comp3, + .vmux = 2, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + }, }; @@ -6914,6 +6935,18 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xd136, .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x6000, + .subdevice = 0x0811, + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x6000, + .subdevice = 0x0911, + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index ca65cda3e101..5fbb4e49495c 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1263,7 +1263,6 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_tvaudio_setmute(dev); saa7134_tvaudio_setvolume(dev, dev->ctl_volume); saa7134_tvaudio_init(dev); - saa7134_tvaudio_do_scan(dev); saa7134_enable_i2s(dev); saa7134_hw_enable2(dev); diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1e4ef1669887..089fa0fb5c94 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -183,9 +183,9 @@ static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe) return 0; } -static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int mt352_pinnacle_tuner_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 off[] = { 0x00, 0xf1}; u8 on[] = { 0x00, 0x71}; struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)}; @@ -196,7 +196,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, /* set frequency (mt2050) */ f.tuner = 0; f.type = V4L2_TUNER_DIGITAL_TV; - f.frequency = params->frequency / 1000 * 16 / 1000; + f.frequency = c->frequency / 1000 * 16 / 1000; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&dev->i2c_adap, &msg, 1); @@ -287,8 +287,9 @@ static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, * these tuners are tu1216, td1316(a) */ -static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tda6651_pll_set(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct saa7134_dev *dev = fe->dvb->priv; struct tda1004x_state *state = fe->demodulator_priv; u8 addr = state->config->tuner_address; @@ -299,7 +300,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ u8 band, cp, filter; /* determine charge pump */ - tuner_frequency = params->frequency + 36166000; + tuner_frequency = c->frequency + 36166000; if (tuner_frequency < 87000000) return -EINVAL; else if (tuner_frequency < 130000000) @@ -324,28 +325,28 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ return -EINVAL; /* determine band */ - if (params->frequency < 49000000) + if (c->frequency < 49000000) return -EINVAL; - else if (params->frequency < 161000000) + else if (c->frequency < 161000000) band = 1; - else if (params->frequency < 444000000) + else if (c->frequency < 444000000) band = 2; - else if (params->frequency < 861000000) + else if (c->frequency < 861000000) band = 4; else return -EINVAL; /* setup PLL filter */ - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: + switch (c->bandwidth_hz) { + case 6000000: filter = 0; break; - case BANDWIDTH_7_MHZ: + case 7000000: filter = 0; break; - case BANDWIDTH_8_MHZ: + case 8000000: filter = 1; break; @@ -356,7 +357,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_ /* calculate divisor * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) */ - tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000; + tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; /* setup tuner buffer */ tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; @@ -436,9 +437,9 @@ static int philips_td1316_tuner_init(struct dvb_frontend *fe) return 0; } -static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_td1316_tuner_set_params(struct dvb_frontend *fe) { - return philips_tda6651_pll_set(fe, params); + return philips_tda6651_pll_set(fe); } static int philips_td1316_tuner_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index d4ee24bf6928..22ecd7297d2d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -235,22 +235,25 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { - unsigned char buf[5], cod4, code3, code4; + unsigned char buf[5]; /* poll IR chip */ if (5 != i2c_master_recv(ir->c, buf, 5)) return -EIO; - cod4 = buf[4]; - code4 = (cod4 >> 2); - code3 = buf[3]; - if (code3 == 0) - /* no key pressed */ + /* Check if some key were pressed */ + if (!(buf[0] & 0x80)) return 0; - /* return key */ - *ir_key = code4; - *ir_raw = code4; + /* + * buf[3] & 0x80 is always high. + * buf[3] & 0x40 is a parity bit. A repeat event is marked + * by preserving it into two separate readings + * buf[4] bits 0 and 1, and buf[1] and buf[2] are always + * zero. + */ + *ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2)); + *ir_raw = *ir_key; return 1; } @@ -752,7 +755,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) polling = 50; /* ms */ break; case SAA7134_BOARD_VIDEOMATE_M1F: - ir_codes = RC_MAP_VIDEOMATE_M1F; + ir_codes = RC_MAP_VIDEOMATE_K100; mask_keycode = 0x0ff00; mask_keyup = 0x040000; break; diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index 57e646bb48b3..b7a99bee2f98 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -332,6 +332,13 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) { __s32 left,right,value; + if (!(dev->tvnorm->id & scan->std)) { + value = 0; + dprintk("skipping %d.%03d MHz [%4s]\n", + scan->carr / 1000, scan->carr % 1000, scan->name); + return 0; + } + if (audio_debug > 1) { int i; dprintk("debug %d:",scan->carr); @@ -348,30 +355,25 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) } printk("\n"); } - if (dev->tvnorm->id & scan->std) { - tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - - tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90); - saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) - return -1; - right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); - - left >>= 16; - right >>= 16; - value = left > right ? left - right : right - left; - dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", - scan->carr / 1000, scan->carr % 1000, - scan->name, value, left, right); - } else { - value = 0; - dprintk("skipping %d.%03d MHz [%4s]\n", - scan->carr / 1000, scan->carr % 1000, scan->name); - } + + tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); + saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) + return -1; + left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + + tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90); + saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) + return -1; + right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); + + left >>= 16; + right >>= 16; + value = left > right ? left - right : right - left; + dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", + scan->carr / 1000, scan->carr % 1000, + scan->name, value, left, right); return value; } @@ -546,6 +548,7 @@ static int tvaudio_thread(void *data) dev->tvnorm->name, carrier/1000, carrier%1000, max1, max2); dev->last_carrier = carrier; + dev->automute = 0; } else if (0 != dev->last_carrier) { /* no carrier -- try last detected one as fallback */ @@ -553,6 +556,7 @@ static int tvaudio_thread(void *data) dprintk("audio carrier scan failed, " "using %d.%03d MHz [last detected]\n", carrier/1000, carrier%1000); + dev->automute = 1; } else { /* no carrier + no fallback -- use default */ @@ -560,9 +564,9 @@ static int tvaudio_thread(void *data) dprintk("audio carrier scan failed, " "using %d.%03d MHz [default]\n", carrier/1000, carrier%1000); + dev->automute = 1; } tvaudio_setcarrier(dev,carrier,carrier); - dev->automute = 0; saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00); saa7134_tvaudio_setmute(dev); /* find the exact tv audio norm */ @@ -601,7 +605,7 @@ static int tvaudio_thread(void *data) if (kthread_should_stop()) break; if (UNSET == dev->thread.mode) { - rx = tvaudio_getstereo(dev,&tvaudio[i]); + rx = tvaudio_getstereo(dev, &tvaudio[audio]); mode = saa7134_tvaudio_rx2mode(rx); } else { mode = dev->thread.mode; @@ -1020,6 +1024,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) } dev->thread.thread = NULL; + dev->thread.scan1 = dev->thread.scan2 = 0; if (my_thread) { saa7134_tvaudio_init(dev); /* start tvaudio thread */ @@ -1029,13 +1034,19 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) dev->name); /* XXX: missing error handling here */ } - saa7134_tvaudio_do_scan(dev); } saa7134_enable_i2s(dev); return 0; } +int saa7134_tvaudio_close(struct saa7134_dev *dev) +{ + dev->automute = 1; + /* anything else to undo? */ + return 0; +} + int saa7134_tvaudio_fini(struct saa7134_dev *dev) { /* shutdown tvaudio thread */ diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 9cf7914f6f90..417034eb6ad2 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1462,6 +1462,8 @@ static int video_release(struct file *file) struct saa6588_command cmd; unsigned long flags; + saa7134_tvaudio_close(dev); + /* turn off overlay */ if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 9b550687213a..42fba4f93c72 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -330,6 +330,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185 #define SAA7134_BOARD_BEHOLD_501 186 #define SAA7134_BOARD_BEHOLD_503FM 187 +#define SAA7134_BOARD_SENSORAY811_911 188 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -817,6 +818,7 @@ void saa7134_tvaudio_init(struct saa7134_dev *dev); int saa7134_tvaudio_init2(struct saa7134_dev *dev); int saa7134_tvaudio_fini(struct saa7134_dev *dev); int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); +int saa7134_tvaudio_close(struct saa7134_dev *dev); int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c index 466e1b02f91f..a7f58a998752 100644 --- a/drivers/media/video/saa7164/saa7164-bus.c +++ b/drivers/media/video/saa7164/saa7164-bus.c @@ -149,7 +149,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, saa7164_bus_verify(dev); msg->size = cpu_to_le16(msg->size); - msg->command = cpu_to_le16(msg->command); + msg->command = cpu_to_le32(msg->command); msg->controlselector = cpu_to_le16(msg->controlselector); if (msg->size > dev->bus.m_wMaxReqSize) { @@ -464,7 +464,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, peekout: msg->size = le16_to_cpu(msg->size); - msg->command = le16_to_cpu(msg->command); + msg->command = le32_to_cpu(msg->command); msg->controlselector = le16_to_cpu(msg->controlselector); ret = SAA_OK; out: diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index c51decfcae19..f854d85a387c 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -786,8 +786,7 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, V4L2_MBUS_DATA_ACTIVE_HIGH) /* Capture is not running, no interrupts, no locking needed */ -static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, - __u32 pixfmt) +static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; @@ -925,11 +924,6 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ceu_write(pcdev, CDOCR, value); ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ - dev_dbg(icd->parent, "S_FMT successful for %c%c%c%c %ux%u\n", - pixfmt & 0xff, (pixfmt >> 8) & 0xff, - (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, - icd->user_width, icd->user_height); - capture_restore(pcdev, capsr); /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ @@ -1966,8 +1960,7 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, if (!ret) { icd->user_width = out_width & ~3; icd->user_height = out_height & ~3; - ret = sh_mobile_ceu_set_bus_param(icd, - icd->current_fmt->host_fmt->fourcc); + ret = sh_mobile_ceu_set_bus_param(icd); } } diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 8a652b53ff7e..05286500b4d4 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -390,18 +390,7 @@ static struct platform_driver __refdata sh_csi2_pdrv = { }, }; -static int __init sh_csi2_init(void) -{ - return platform_driver_register(&sh_csi2_pdrv); -} - -static void __exit sh_csi2_exit(void) -{ - platform_driver_unregister(&sh_csi2_pdrv); -} - -module_init(sh_csi2_init); -module_exit(sh_csi2_exit); +module_platform_driver(sh_csi2_pdrv); MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver"); MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 7025be129286..c2882fa5be85 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -75,8 +75,8 @@ MODULE_PARM_DESC(video_nr, "\none and for every other camera." "\n"); -static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = - SN9C102_FORCE_MUNMAP}; +static bool force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = + SN9C102_FORCE_MUNMAP}; module_param_array(force_munmap, bool, NULL, 0444); MODULE_PARM_DESC(force_munmap, " <0|1[,...]>" diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 62e4312515cb..b82710745ba8 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -487,7 +487,7 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, icd->user_width, icd->user_height); /* set physical bus parameters */ - return ici->ops->set_bus_param(icd, pix->pixelformat); + return ici->ops->set_bus_param(icd); } static int soc_camera_open(struct file *file) @@ -600,9 +600,9 @@ static int soc_camera_close(struct file *file) pm_runtime_suspend(&icd->vdev->dev); pm_runtime_disable(&icd->vdev->dev); - ici->ops->remove(icd); if (ici->ops->init_videobuf2) vb2_queue_release(&icd->vb2_vidq); + ici->ops->remove(icd); soc_camera_power_off(icd, icl); } diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 4402a8a74f7a..f59ccade07c8 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -189,18 +189,7 @@ static struct platform_driver soc_camera_platform_driver = { .remove = soc_camera_platform_remove, }; -static int __init soc_camera_platform_module_init(void) -{ - return platform_driver_register(&soc_camera_platform_driver); -} - -static void __exit soc_camera_platform_module_exit(void) -{ - platform_driver_unregister(&soc_camera_platform_driver); -} - -module_init(soc_camera_platform_module_init); -module_exit(soc_camera_platform_module_exit); +module_platform_driver(soc_camera_platform_driver); MODULE_DESCRIPTION("SoC Camera Platform driver"); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index b7fb5a5cad7e..d427f8436c70 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -38,11 +38,11 @@ #include "stk-webcam.h" -static int hflip = 1; +static bool hflip = 1; module_param(hflip, bool, 0444); MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1"); -static int vflip = 1; +static bool vflip = 1; module_param(vflip, bool, 0444); MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1"); @@ -377,8 +377,8 @@ static int stk_prepare_iso(struct stk_camera *dev) if (dev->isobufs) STK_ERROR("isobufs already allocated. Bad\n"); else - dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs), - GFP_KERNEL); + dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs), + GFP_KERNEL); if (dev->isobufs == NULL) { STK_ERROR("Unable to allocate iso buffers\n"); return -ENOMEM; diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c index a0895bf07487..0a2d75f04066 100644 --- a/drivers/media/video/timblogiw.c +++ b/drivers/media/video/timblogiw.c @@ -872,20 +872,7 @@ static struct platform_driver timblogiw_platform_driver = { .remove = __devexit_p(timblogiw_remove), }; -/* Module functions */ - -static int __init timblogiw_init(void) -{ - return platform_driver_register(&timblogiw_platform_driver); -} - -static void __exit timblogiw_exit(void) -{ - platform_driver_unregister(&timblogiw_platform_driver); -} - -module_init(timblogiw_init); -module_exit(timblogiw_exit); +module_platform_driver(timblogiw_platform_driver); MODULE_DESCRIPTION(TIMBLOGIWIN_NAME); MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>"); diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h index 56564e6aaac2..5dd73b7857d1 100644 --- a/drivers/media/video/tlg2300/pd-common.h +++ b/drivers/media/video/tlg2300/pd-common.h @@ -140,7 +140,7 @@ struct pd_dvb_adapter { u8 reserved[3]; /* data for power resume*/ - struct dvb_frontend_parameters fe_param; + struct dtv_frontend_properties fe_param; /* for channel scanning */ int prev_freq; diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c index d0da11ae19df..30fcb117e898 100644 --- a/drivers/media/video/tlg2300/pd-dvb.c +++ b/drivers/media/video/tlg2300/pd-dvb.c @@ -12,9 +12,9 @@ static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb); static int dvb_bandwidth[][2] = { - { TLG_BW_8, BANDWIDTH_8_MHZ }, - { TLG_BW_7, BANDWIDTH_7_MHZ }, - { TLG_BW_6, BANDWIDTH_6_MHZ } + { TLG_BW_8, 8000000 }, + { TLG_BW_7, 7000000 }, + { TLG_BW_6, 6000000 } }; static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth); @@ -146,9 +146,9 @@ static int fw_delay_overflow(struct pd_dvb_adapter *adapter) return msec > 800 ? true : false; } -static int poseidon_set_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int poseidon_set_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; s32 ret = 0, cmd_status = 0; s32 i, bandwidth = -1; struct poseidon *pd = fe->demodulator_priv; @@ -159,7 +159,7 @@ static int poseidon_set_fe(struct dvb_frontend *fe, mutex_lock(&pd->lock); for (i = 0; i < dvb_bandwidth_length; i++) - if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1]) + if (fep->bandwidth_hz == dvb_bandwidth[i][1]) bandwidth = dvb_bandwidth[i][0]; if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) { @@ -210,7 +210,7 @@ static int pm_dvb_resume(struct poseidon *pd) poseidon_check_mode_dvbt(pd); msleep(300); - poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param); + poseidon_set_fe(&pd_dvb->dvb_fe); dvb_start_streaming(pd_dvb); return 0; @@ -227,13 +227,13 @@ static s32 poseidon_fe_init(struct dvb_frontend *fe) pd->pm_resume = pm_dvb_resume; #endif memset(&pd_dvb->fe_param, 0, - sizeof(struct dvb_frontend_parameters)); + sizeof(struct dtv_frontend_properties)); return 0; } -static int poseidon_get_fe(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) +static int poseidon_get_fe(struct dvb_frontend *fe) { + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct poseidon *pd = fe->demodulator_priv; struct pd_dvb_adapter *pd_dvb = &pd->dvb_data; @@ -332,9 +332,9 @@ static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) } static struct dvb_frontend_ops poseidon_frontend_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Poseidon DVB-T", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 62500,/* FIXME */ diff --git a/drivers/media/video/tm6000/Kconfig b/drivers/media/video/tm6000/Kconfig index 114eec8a630a..a43b77abd931 100644 --- a/drivers/media/video/tm6000/Kconfig +++ b/drivers/media/video/tm6000/Kconfig @@ -1,6 +1,6 @@ config VIDEO_TM6000 tristate "TV Master TM5600/6000/6010 driver" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB && EXPERIMENTAL + depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB select VIDEO_TUNER select MEDIA_TUNER_XC2028 select MEDIA_TUNER_XC5000 @@ -16,7 +16,7 @@ config VIDEO_TM6000 config VIDEO_TM6000_ALSA tristate "TV Master TM5600/6000/6010 audio support" - depends on VIDEO_TM6000 && SND && EXPERIMENTAL + depends on VIDEO_TM6000 && SND select SND_PCM ---help--- This is a video4linux driver for direct (DMA) audio for @@ -27,7 +27,7 @@ config VIDEO_TM6000_ALSA config VIDEO_TM6000_DVB tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB && EXPERIMENTAL + depends on VIDEO_TM6000 && DVB_CORE && USB select DVB_ZL10353 ---help--- This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/media/video/tm6000/tm6000-alsa.c b/drivers/media/video/tm6000/tm6000-alsa.c index 7d675c72fd47..bd07ec707956 100644 --- a/drivers/media/video/tm6000/tm6000-alsa.c +++ b/drivers/media/video/tm6000/tm6000-alsa.c @@ -42,7 +42,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; +static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled."); @@ -146,20 +146,21 @@ static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size) #define DEFAULT_FIFO_SIZE 4096 static struct snd_pcm_hardware snd_tm6000_digital_hw = { - .info = SNDRV_PCM_INFO_MMAP | + .info = SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, .rate_min = 48000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .period_bytes_min = 64, .period_bytes_max = 12544, - .periods_min = 1, + .periods_min = 2, .periods_max = 98, .buffer_bytes_max = 62720 * 8, }; @@ -181,6 +182,7 @@ static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream) chip->substream = substream; runtime->hw = snd_tm6000_digital_hw; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); return 0; _error: @@ -347,9 +349,13 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd) int err = 0; switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ + case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ case SNDRV_PCM_TRIGGER_START: atomic_set(&core->stream_started, 1); break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ + case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ case SNDRV_PCM_TRIGGER_STOP: atomic_set(&core->stream_started, 0); break; @@ -371,6 +377,14 @@ static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream) return chip->buf_pos; } +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + /* * operators */ @@ -383,6 +397,7 @@ static struct snd_pcm_ops snd_tm6000_pcm_ops = { .prepare = snd_tm6000_prepare, .trigger = snd_tm6000_card_trigger, .pointer = snd_tm6000_pointer, + .page = snd_pcm_get_vmalloc_page, }; /* diff --git a/drivers/media/video/tm6000/tm6000-cards.c b/drivers/media/video/tm6000/tm6000-cards.c index ff939bc0e0b9..034659b13174 100644 --- a/drivers/media/video/tm6000/tm6000-cards.c +++ b/drivers/media/video/tm6000/tm6000-cards.c @@ -351,6 +351,7 @@ static struct tm6000_board tm6000_boards[] = { .tuner_addr = 0xc2 >> 1, .demod_addr = 0x1e >> 1, .type = TM6010, + .ir_codes = RC_MAP_HAUPPAUGE, .caps = { .has_tuner = 1, .has_dvb = 1, @@ -639,6 +640,7 @@ static struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, { } }; +MODULE_DEVICE_TABLE(usb, tm6000_id_table); /* Control power led for show some activity */ void tm6000_flash_led(struct tm6000_core *dev, u8 state) @@ -941,6 +943,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev) case TM6010_BOARD_HAUPPAUGE_900H: case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: case TM6010_BOARD_TWINHAN_TU501: + ctl.max_len = 80; ctl.fname = "xc3028L-v36.fw"; break; default: @@ -1002,6 +1005,7 @@ static int fill_board_specific_data(struct tm6000_core *dev) /* setup per-model quirks */ switch (dev->model) { case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE: + case TM6010_BOARD_HAUPPAUGE_900H: dev->quirks |= TM6000_QUIRK_NO_USB_DELAY; break; @@ -1050,6 +1054,33 @@ static void use_alternative_detection_method(struct tm6000_core *dev) tm6000_boards[model].name, model); } +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct tm6000_core *dev = container_of(work, struct tm6000_core, + request_module_wk); + + request_module("tm6000-alsa"); + + if (dev->caps.has_dvb) + request_module("tm6000-dvb"); +} + +static void request_modules(struct tm6000_core *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); +} + +static void flush_request_modules(struct tm6000_core *dev) +{ + flush_work_sync(&dev->request_module_wk); +} +#else +#define request_modules(dev) +#define flush_request_modules(dev) +#endif /* CONFIG_MODULES */ + static int tm6000_init_dev(struct tm6000_core *dev) { struct v4l2_frequency f; @@ -1112,6 +1143,8 @@ static int tm6000_init_dev(struct tm6000_core *dev) tm6000_ir_init(dev); + request_modules(dev); + mutex_unlock(&dev->lock); return 0; @@ -1324,6 +1357,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name); + flush_request_modules(dev); + tm6000_ir_fini(dev); if (dev->gpio.power_led) { diff --git a/drivers/media/video/tm6000/tm6000-core.c b/drivers/media/video/tm6000/tm6000-core.c index 9783616a0da2..22cc0116deb6 100644 --- a/drivers/media/video/tm6000/tm6000-core.c +++ b/drivers/media/video/tm6000/tm6000-core.c @@ -38,6 +38,7 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, int ret, i; unsigned int pipe; u8 *data = NULL; + int delay = 5000; mutex_lock(&dev->usb_lock); @@ -88,7 +89,20 @@ int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, } kfree(data); - msleep(5); + + if (dev->quirks & TM6000_QUIRK_NO_USB_DELAY) + delay = 0; + + if (req == REQ_16_SET_GET_I2C_WR1_RDN && !(req_type & USB_DIR_IN)) { + unsigned int tsleep; + /* Calculate delay time, 14000us for 64 bytes */ + tsleep = (len * 200) + 200; + if (tsleep < delay) + tsleep = delay; + usleep_range(tsleep, tsleep + 1000); + } + else if (delay) + usleep_range(delay, delay + 1000); mutex_unlock(&dev->usb_lock); return ret; @@ -125,14 +139,14 @@ int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, u8 new_index; rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, - value, index, buf, 1); + value, 0, buf, 1); if (rc < 0) return rc; new_index = (buf[0] & ~mask) | (index & mask); - if (new_index == index) + if (new_index == buf[0]) return 0; return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, @@ -536,16 +550,16 @@ static struct reg_init tm6010_init_tab[] = { { TM6010_REQ05_R18_IMASK7, 0x00 }, - { TM6010_REQ07_RD8_IR_LEADER1, 0xaa }, - { TM6010_REQ07_RD8_IR_LEADER0, 0x30 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 }, - { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 }, + { TM6010_REQ07_RDC_IR_LEADER1, 0xaa }, + { TM6010_REQ07_RDD_IR_LEADER0, 0x30 }, + { TM6010_REQ07_RDE_IR_PULSE_CNT1, 0x20 }, + { TM6010_REQ07_RDF_IR_PULSE_CNT0, 0xd0 }, { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, - { TM6010_REQ07_RD8_IR, 0x2f }, + { TM6010_REQ07_RD8_IR, 0x0f }, /* set remote wakeup key:any key wakeup */ { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, - { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff }, + { TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff }, }; int tm6000_init(struct tm6000_core *dev) @@ -599,55 +613,6 @@ int tm6000_init(struct tm6000_core *dev) return rc; } -int tm6000_reset(struct tm6000_core *dev) -{ - int pipe; - int err; - - msleep(500); - - err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 0); - if (err < 0) { - tm6000_err("failed to select interface %d, alt. setting 0\n", - dev->isoc_in.bInterfaceNumber); - return err; - } - - err = usb_reset_configuration(dev->udev); - if (err < 0) { - tm6000_err("failed to reset configuration\n"); - return err; - } - - if ((dev->quirks & TM6000_QUIRK_NO_USB_DELAY) == 0) - msleep(5); - - /* - * Not all devices have int_in defined - */ - if (!dev->int_in.endp) - return 0; - - err = usb_set_interface(dev->udev, dev->isoc_in.bInterfaceNumber, 2); - if (err < 0) { - tm6000_err("failed to select interface %d, alt. setting 2\n", - dev->isoc_in.bInterfaceNumber); - return err; - } - - msleep(5); - - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - - err = usb_clear_halt(dev->udev, pipe); - if (err < 0) { - tm6000_err("usb_clear_halt failed: %d\n", err); - return err; - } - - return 0; -} int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) { @@ -696,11 +661,13 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) if (dev->dev_type == TM6010) { /* Audio crossbar setting, default SIF1 */ u8 areg_f0; + u8 areg_07 = 0x10; switch (dev->rinput.amux) { case TM6000_AMUX_SIF1: case TM6000_AMUX_SIF2: areg_f0 = 0x03; + areg_07 = 0x30; break; case TM6000_AMUX_ADC1: areg_f0 = 0x00; @@ -720,6 +687,9 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) /* Set audio input crossbar */ tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, areg_f0, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + areg_07, 0xf0); } else { u8 areg_eb; /* Audio setting, default LINE1 */ diff --git a/drivers/media/video/tm6000/tm6000-dvb.c b/drivers/media/video/tm6000/tm6000-dvb.c index 5e6c129a4beb..e1f3f66e1e63 100644 --- a/drivers/media/video/tm6000/tm6000-dvb.c +++ b/drivers/media/video/tm6000/tm6000-dvb.c @@ -89,9 +89,19 @@ static void tm6000_urb_received(struct urb *urb) int ret; struct tm6000_core *dev = urb->context; - if (urb->status != 0) + switch (urb->status) { + case 0: + case -ETIMEDOUT: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + return; + default: print_err_status(dev, 0, urb->status); - else if (urb->actual_length > 0) + } + + if (urb->actual_length > 0) dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer, urb->actual_length); @@ -151,7 +161,7 @@ static int tm6000_start_stream(struct tm6000_core *dev) printk(KERN_ERR "tm6000: pipe resetted\n"); /* mutex_lock(&tm6000_driver.open_close_mutex); */ - ret = usb_submit_urb(dvb->bulk_urb, GFP_KERNEL); + ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC); /* mutex_unlock(&tm6000_driver.open_close_mutex); */ if (ret) { @@ -396,6 +406,11 @@ static int dvb_init(struct tm6000_core *dev) if (!dev->caps.has_dvb) return 0; + if (dev->udev->speed == USB_SPEED_FULL) { + printk(KERN_INFO "This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)\n"); + return 0; + } + dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); if (!dvb) { printk(KERN_INFO "Cannot allocate memory\n"); diff --git a/drivers/media/video/tm6000/tm6000-i2c.c b/drivers/media/video/tm6000/tm6000-i2c.c index 0290bbf00c3e..c7e23e3dd75e 100644 --- a/drivers/media/video/tm6000/tm6000-i2c.c +++ b/drivers/media/video/tm6000/tm6000-i2c.c @@ -46,11 +46,10 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, __u8 reg, char *buf, int len) { int rc; - unsigned int tsleep; unsigned int i2c_packet_limit = 16; if (dev->dev_type == TM6010) - i2c_packet_limit = 64; + i2c_packet_limit = 80; if (!buf) return -1; @@ -71,10 +70,6 @@ static int tm6000_i2c_send_regs(struct tm6000_core *dev, unsigned char addr, return rc; } - /* Calculate delay time, 14000us for 64 bytes */ - tsleep = ((len * 200) + 200 + 1000) / 1000; - msleep(tsleep); - /* release mutex */ return rc; } @@ -145,7 +140,6 @@ static int tm6000_i2c_recv_regs16(struct tm6000_core *dev, unsigned char addr, return rc; } - msleep(1400 / 1000); rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, REQ_35_AFTEK_TUNER_READ, reg, 0, buf, len); diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c index 405d12729d05..7844607dd45a 100644 --- a/drivers/media/video/tm6000/tm6000-input.c +++ b/drivers/media/video/tm6000/tm6000-input.c @@ -31,22 +31,25 @@ static unsigned int ir_debug; module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debug message [IR]"); +MODULE_PARM_DESC(ir_debug, "debug message level"); static unsigned int enable_ir = 1; module_param(enable_ir, int, 0644); MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); -/* number of 50ms for ON-OFF-ON power led */ -/* show IR activity */ -#define PWLED_OFF 2 +static unsigned int ir_clock_mhz = 12; +module_param(ir_clock_mhz, int, 0644); +MODULE_PARM_DESC(enable_ir, "ir clock, in MHz"); + +#define URB_SUBMIT_DELAY 100 /* ms - Delay to submit an URB request on retrial and init */ +#define URB_INT_LED_DELAY 100 /* ms - Delay to turn led on again on int mode */ #undef dprintk -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ +#define dprintk(level, fmt, arg...) do {\ + if (ir_debug >= level) \ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } + } while (0) struct tm6000_ir_poll_result { u16 rc_data; @@ -62,20 +65,15 @@ struct tm6000_IR { int polling; struct delayed_work work; u8 wait:1; - u8 key:1; - u8 pwled:1; - u8 pwledcnt; + u8 pwled:2; + u8 submit_urb:1; u16 key_addr; struct urb *int_urb; - u8 *urb_data; - - int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *); /* IR device properties */ u64 rc_type; }; - void tm6000_ir_wait(struct tm6000_core *dev, u8 state) { struct tm6000_IR *ir = dev->ir; @@ -83,62 +81,84 @@ void tm6000_ir_wait(struct tm6000_core *dev, u8 state) if (!dev->ir) return; + dprintk(2, "%s: %i\n",__func__, ir->wait); + if (state) ir->wait = 1; else ir->wait = 0; } - static int tm6000_ir_config(struct tm6000_IR *ir) { struct tm6000_core *dev = ir->dev; - u8 buf[10]; - int rc; + u32 pulse = 0, leader = 0; + + dprintk(2, "%s\n",__func__); + + /* + * The IR decoder supports RC-5 or NEC, with a configurable timing. + * The timing configuration there is not that accurate, as it uses + * approximate values. The NEC spec mentions a 562.5 unit period, + * and RC-5 uses a 888.8 period. + * Currently, driver assumes a clock provided by a 12 MHz XTAL, but + * a modprobe parameter can adjust it. + * Adjustments are required for other timings. + * It seems that the 900ms timing for NEC is used to detect a RC-5 + * IR, in order to discard such decoding + */ switch (ir->rc_type) { case RC_TYPE_NEC: - /* Setup IR decoder for NEC standard 12MHz system clock */ - /* IR_LEADER_CNT = 0.9ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30); - /* IR_PULSE_CNT = 0.7ms */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0); - /* Remote WAKEUP = enable */ - tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); - /* IR_WKUP_SEL = Low byte in decoded IR data */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff); - /* IR_WKU_ADD code */ - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff); - tm6000_flash_led(dev, 0); - msleep(100); - tm6000_flash_led(dev, 1); + leader = 900; /* ms */ + pulse = 700; /* ms - the actual value would be 562 */ break; default: - /* hack */ - buf[0] = 0xff; - buf[1] = 0xff; - buf[2] = 0xf2; - buf[3] = 0x2b; - buf[4] = 0x20; - buf[5] = 0x35; - buf[6] = 0x60; - buf[7] = 0x04; - buf[8] = 0xc0; - buf[9] = 0x08; - - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); - msleep(100); - - if (rc < 0) { - printk(KERN_INFO "IR configuration failed"); - return rc; - } + case RC_TYPE_RC5: + leader = 900; /* ms - from the NEC decoding */ + pulse = 1780; /* ms - The actual value would be 1776 */ break; } + pulse = ir_clock_mhz * pulse; + leader = ir_clock_mhz * leader; + if (ir->rc_type == RC_TYPE_NEC) + leader = leader | 0x8000; + + dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n", + __func__, + (ir->rc_type == RC_TYPE_NEC) ? "NEC" : "RC-5", + ir_clock_mhz, leader, pulse); + + /* Remote WAKEUP = enable, normal mode, from IR decoder output */ + tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); + + /* Enable IR reception on non-busrt mode */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR, 0x2f); + + /* IR_WKUP_SEL = Low byte in decoded IR data */ + tm6000_set_reg(dev, TM6010_REQ07_RDA_IR_WAKEUP_SEL, 0xff); + /* IR_WKU_ADD code */ + tm6000_set_reg(dev, TM6010_REQ07_RDB_IR_WAKEUP_ADD, 0xff); + + tm6000_set_reg(dev, TM6010_REQ07_RDC_IR_LEADER1, leader >> 8); + tm6000_set_reg(dev, TM6010_REQ07_RDD_IR_LEADER0, leader); + + tm6000_set_reg(dev, TM6010_REQ07_RDE_IR_PULSE_CNT1, pulse >> 8); + tm6000_set_reg(dev, TM6010_REQ07_RDF_IR_PULSE_CNT0, pulse); + + if (!ir->polling) + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); + else + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); + msleep(10); + + /* Shows that IR is working via the LED */ + tm6000_flash_led(dev, 0); + msleep(100); + tm6000_flash_led(dev, 1); + ir->pwled = 1; + return 0; } @@ -146,132 +166,124 @@ static void tm6000_ir_urb_received(struct urb *urb) { struct tm6000_core *dev = urb->context; struct tm6000_IR *ir = dev->ir; + struct tm6000_ir_poll_result poll_result; + char *buf; int rc; - if (urb->status != 0) - printk(KERN_INFO "not ready\n"); - else if (urb->actual_length > 0) { - memcpy(ir->urb_data, urb->transfer_buffer, urb->actual_length); + dprintk(2, "%s\n",__func__); + if (urb->status < 0 || urb->actual_length <= 0) { + printk(KERN_INFO "tm6000: IR URB failure: status: %i, length %i\n", + urb->status, urb->actual_length); + ir->submit_urb = 1; + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); + return; + } + buf = urb->transfer_buffer; - dprintk("data %02x %02x %02x %02x\n", ir->urb_data[0], - ir->urb_data[1], ir->urb_data[2], ir->urb_data[3]); + if (ir_debug) + print_hex_dump(KERN_DEBUG, "tm6000: IR data: ", + DUMP_PREFIX_OFFSET,16, 1, + buf, urb->actual_length, false); - ir->key = 1; - } + poll_result.rc_data = buf[0]; + if (urb->actual_length > 1) + poll_result.rc_data |= buf[1] << 8; + + dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data); + rc_keydown(ir->rc, poll_result.rc_data, 0); rc = usb_submit_urb(urb, GFP_ATOMIC); + /* + * Flash the led. We can't do it here, as it is running on IRQ context. + * So, use the scheduler to do it, in a few ms. + */ + ir->pwled = 2; + schedule_delayed_work(&ir->work, msecs_to_jiffies(10)); } -static int default_polling_getkey(struct tm6000_IR *ir, - struct tm6000_ir_poll_result *poll_result) +static void tm6000_ir_handle_key(struct work_struct *work) { + struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); struct tm6000_core *dev = ir->dev; + struct tm6000_ir_poll_result poll_result; int rc; u8 buf[2]; - if (ir->wait && !&dev->int_in) - return 0; - - if (&dev->int_in) { - switch (ir->rc_type) { - case RC_TYPE_RC5: - poll_result->rc_data = ir->urb_data[0]; - break; - case RC_TYPE_NEC: - if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) { - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - } - break; - default: - poll_result->rc_data = ir->urb_data[0] - | ir->urb_data[1] << 8; - break; - } - } else { - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - msleep(10); - tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); - msleep(10); - - if (ir->rc_type == RC_TYPE_RC5) { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 1); - - msleep(10); - - dprintk("read data=%02x\n", buf[0]); - if (rc < 0) - return rc; + if (ir->wait) + return; - poll_result->rc_data = buf[0]; - } else { - rc = tm6000_read_write_usb(dev, USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE, - REQ_02_GET_IR_CODE, 0, 0, buf, 2); + dprintk(3, "%s\n",__func__); - msleep(10); + rc = tm6000_read_write_usb(dev, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + REQ_02_GET_IR_CODE, 0, 0, buf, 2); + if (rc < 0) + return; - dprintk("read data=%04x\n", buf[0] | buf[1] << 8); - if (rc < 0) - return rc; + if (rc > 1) + poll_result.rc_data = buf[0] | buf[1] << 8; + else + poll_result.rc_data = buf[0]; - poll_result->rc_data = buf[0] | buf[1] << 8; + /* Check if something was read */ + if ((poll_result.rc_data & 0xff) == 0xff) { + if (!ir->pwled) { + tm6000_flash_led(dev, 1); + ir->pwled = 1; } - if ((poll_result->rc_data & 0x00ff) != 0xff) - ir->key = 1; + return; } - return 0; + + dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data); + rc_keydown(ir->rc, poll_result.rc_data, 0); + tm6000_flash_led(dev, 0); + ir->pwled = 0; + + /* Re-schedule polling */ + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } -static void tm6000_ir_handle_key(struct tm6000_IR *ir) +static void tm6000_ir_int_work(struct work_struct *work) { + struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); struct tm6000_core *dev = ir->dev; - int result; - struct tm6000_ir_poll_result poll_result; + int rc; - /* read the registers containing the IR status */ - result = ir->get_key(ir, &poll_result); - if (result < 0) { - printk(KERN_INFO "ir->get_key() failed %d\n", result); - return; - } + dprintk(3, "%s, submit_urb = %d, pwled = %d\n",__func__, ir->submit_urb, + ir->pwled); - dprintk("ir->get_key result data=%04x\n", poll_result.rc_data); + if (ir->submit_urb) { + dprintk(3, "Resubmit urb\n"); + tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); - if (ir->pwled) { - if (ir->pwledcnt >= PWLED_OFF) { - ir->pwled = 0; - ir->pwledcnt = 0; - tm6000_flash_led(dev, 1); - } else - ir->pwledcnt += 1; + rc = usb_submit_urb(ir->int_urb, GFP_ATOMIC); + if (rc < 0) { + printk(KERN_ERR "tm6000: Can't submit an IR interrupt. Error %i\n", + rc); + /* Retry in 100 ms */ + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); + return; + } + ir->submit_urb = 0; } - if (ir->key) { - rc_keydown(ir->rc, poll_result.rc_data, 0); - ir->key = 0; - ir->pwled = 1; - ir->pwledcnt = 0; + /* Led is enabled only if USB submit doesn't fail */ + if (ir->pwled == 2) { tm6000_flash_led(dev, 0); + ir->pwled = 0; + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_INT_LED_DELAY)); + } else if (!ir->pwled) { + tm6000_flash_led(dev, 1); + ir->pwled = 1; } - return; -} - -static void tm6000_ir_work(struct work_struct *work) -{ - struct tm6000_IR *ir = container_of(work, struct tm6000_IR, work.work); - - tm6000_ir_handle_key(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } static int tm6000_ir_start(struct rc_dev *rc) { struct tm6000_IR *ir = rc->priv; - INIT_DELAYED_WORK(&ir->work, tm6000_ir_work); + dprintk(2, "%s\n",__func__); + schedule_delayed_work(&ir->work, 0); return 0; @@ -281,6 +293,8 @@ static void tm6000_ir_stop(struct rc_dev *rc) { struct tm6000_IR *ir = rc->priv; + dprintk(2, "%s\n",__func__); + cancel_delayed_work_sync(&ir->work); } @@ -291,10 +305,11 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) if (!ir) return 0; + dprintk(2, "%s\n",__func__); + if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); - ir->get_key = default_polling_getkey; ir->rc_type = rc_type; tm6000_ir_config(ir); @@ -302,17 +317,19 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) return 0; } -int tm6000_ir_int_start(struct tm6000_core *dev) +static int __tm6000_ir_int_start(struct rc_dev *rc) { - struct tm6000_IR *ir = dev->ir; + struct tm6000_IR *ir = rc->priv; + struct tm6000_core *dev = ir->dev; int pipe, size; int err = -ENOMEM; - if (!ir) return -ENODEV; - ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); + dprintk(2, "%s\n",__func__); + + ir->int_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!ir->int_urb) return -ENOMEM; @@ -321,42 +338,59 @@ int tm6000_ir_int_start(struct tm6000_core *dev) & USB_ENDPOINT_NUMBER_MASK); size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - dprintk("IR max size: %d\n", size); + dprintk(1, "IR max size: %d\n", size); - ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); + ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC); if (ir->int_urb->transfer_buffer == NULL) { usb_free_urb(ir->int_urb); return err; } - dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); + dprintk(1, "int interval: %d\n", dev->int_in.endp->desc.bInterval); + usb_fill_int_urb(ir->int_urb, dev->udev, pipe, ir->int_urb->transfer_buffer, size, tm6000_ir_urb_received, dev, dev->int_in.endp->desc.bInterval); - err = usb_submit_urb(ir->int_urb, GFP_KERNEL); - if (err) { - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - return err; - } - ir->urb_data = kzalloc(size, GFP_KERNEL); + + ir->submit_urb = 1; + schedule_delayed_work(&ir->work, msecs_to_jiffies(URB_SUBMIT_DELAY)); return 0; } -void tm6000_ir_int_stop(struct tm6000_core *dev) +static void __tm6000_ir_int_stop(struct rc_dev *rc) { - struct tm6000_IR *ir = dev->ir; + struct tm6000_IR *ir = rc->priv; - if (!ir) + if (!ir || !ir->int_urb) return; + dprintk(2, "%s\n",__func__); + usb_kill_urb(ir->int_urb); kfree(ir->int_urb->transfer_buffer); usb_free_urb(ir->int_urb); ir->int_urb = NULL; - kfree(ir->urb_data); - ir->urb_data = NULL; +} + +int tm6000_ir_int_start(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + if (!ir) + return 0; + + return __tm6000_ir_int_start(ir->rc); +} + +void tm6000_ir_int_stop(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + if (!ir || !ir->rc) + return; + + __tm6000_ir_int_stop(ir->rc); } int tm6000_ir_init(struct tm6000_core *dev) @@ -374,29 +408,36 @@ int tm6000_ir_init(struct tm6000_core *dev) if (!dev->ir_codes) return 0; - ir = kzalloc(sizeof(*ir), GFP_KERNEL); + ir = kzalloc(sizeof(*ir), GFP_ATOMIC); rc = rc_allocate_device(); if (!ir || !rc) goto out; + dprintk(2, "%s\n", __func__); + /* record handles to ourself */ ir->dev = dev; dev->ir = ir; ir->rc = rc; - /* input einrichten */ + /* input setup */ rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + /* Neded, in order to support NEC remotes with 24 or 32 bits */ + rc->scanmask = 0xffff; rc->priv = ir; rc->change_protocol = tm6000_ir_change_protocol; - rc->open = tm6000_ir_start; - rc->close = tm6000_ir_stop; + if (dev->int_in.endp) { + rc->open = __tm6000_ir_int_start; + rc->close = __tm6000_ir_int_stop; + INIT_DELAYED_WORK(&ir->work, tm6000_ir_int_work); + } else { + rc->open = tm6000_ir_start; + rc->close = tm6000_ir_stop; + ir->polling = 50; + INIT_DELAYED_WORK(&ir->work, tm6000_ir_handle_key); + } rc->driver_type = RC_DRIVER_SCANCODE; - ir->polling = 50; - ir->pwled = 0; - ir->pwledcnt = 0; - - snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", dev->name); @@ -415,15 +456,6 @@ int tm6000_ir_init(struct tm6000_core *dev) rc->driver_name = "tm6000"; rc->dev.parent = &dev->udev->dev; - if (&dev->int_in) { - dprintk("IR over int\n"); - - err = tm6000_ir_int_start(dev); - - if (err) - goto out; - } - /* ir register */ err = rc_register_device(rc); if (err) @@ -447,10 +479,19 @@ int tm6000_ir_fini(struct tm6000_core *dev) if (!ir) return 0; + dprintk(2, "%s\n",__func__); + rc_unregister_device(ir->rc); - if (ir->int_urb) - tm6000_ir_int_stop(dev); + if (!ir->polling) + __tm6000_ir_int_stop(ir->rc); + + tm6000_ir_stop(ir->rc); + + /* Turn off the led */ + tm6000_flash_led(dev, 0); + ir->pwled = 0; + kfree(ir); dev->ir = NULL; diff --git a/drivers/media/video/tm6000/tm6000-regs.h b/drivers/media/video/tm6000/tm6000-regs.h index 7f491b6de933..a38c251ed57b 100644 --- a/drivers/media/video/tm6000/tm6000-regs.h +++ b/drivers/media/video/tm6000/tm6000-regs.h @@ -284,19 +284,19 @@ enum { /* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR 0x07, 0xd8 /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9 +#define TM6010_REQ07_RD9_IR_BSIZE 0x07, 0xd9 /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda +#define TM6010_REQ07_RDA_IR_WAKEUP_SEL 0x07, 0xda /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb +#define TM6010_REQ07_RDB_IR_WAKEUP_ADD 0x07, 0xdb /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc +#define TM6010_REQ07_RDC_IR_LEADER1 0x07, 0xdc /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd +#define TM6010_REQ07_RDD_IR_LEADER0 0x07, 0xdd /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde +#define TM6010_REQ07_RDE_IR_PULSE_CNT1 0x07, 0xde /* ONLY for TM6010 */ -#define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf +#define TM6010_REQ07_RDF_IR_PULSE_CNT0 0x07, 0xdf /* ONLY for TM6010 */ #define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 /* ONLY for TM6010 */ diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c index 9a4145dc3d87..9dc0831d813f 100644 --- a/drivers/media/video/tm6000/tm6000-stds.c +++ b/drivers/media/video/tm6000/tm6000-stds.c @@ -361,82 +361,51 @@ static int tm6000_set_audio_std(struct tm6000_core *dev) return 0; } - switch (tm6010_a_mode) { + /* + * STD/MN shouldn't be affected by tm6010_a_mode, as there's just one + * audio standard for each V4L2_STD type. + */ + if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_KR) { + areg_05 |= 0x04; + } else if ((dev->norm & V4L2_STD_NTSC) == V4L2_STD_NTSC_M_JP) { + areg_05 |= 0x43; + } else if (dev->norm & V4L2_STD_MN) { + areg_05 |= 0x22; + } else switch (tm6010_a_mode) { /* auto */ case 0: - switch (dev->norm) { - case V4L2_STD_NTSC_M_KR: + if ((dev->norm & V4L2_STD_SECAM) == V4L2_STD_SECAM_L) areg_05 |= 0x00; - break; - case V4L2_STD_NTSC_M_JP: - areg_05 |= 0x40; - break; - case V4L2_STD_NTSC_M: - case V4L2_STD_PAL_M: - case V4L2_STD_PAL_N: - areg_05 |= 0x20; - break; - case V4L2_STD_PAL_Nc: - areg_05 |= 0x60; - break; - case V4L2_STD_SECAM_L: - areg_05 |= 0x00; - break; - case V4L2_STD_DK: + else /* Other PAL/SECAM standards */ areg_05 |= 0x10; - break; - } break; /* A2 */ case 1: - switch (dev->norm) { - case V4L2_STD_B: - case V4L2_STD_GH: - areg_05 = 0x05; - break; - case V4L2_STD_DK: + if (dev->norm & V4L2_STD_DK) areg_05 = 0x09; - break; - } + else + areg_05 = 0x05; break; /* NICAM */ case 2: - switch (dev->norm) { - case V4L2_STD_B: - case V4L2_STD_GH: - areg_05 = 0x07; - break; - case V4L2_STD_DK: + if (dev->norm & V4L2_STD_DK) { areg_05 = 0x06; - break; - case V4L2_STD_PAL_I: + } else if (dev->norm & V4L2_STD_PAL_I) { areg_05 = 0x08; - break; - case V4L2_STD_SECAM_L: + } else if (dev->norm & V4L2_STD_SECAM_L) { areg_05 = 0x0a; areg_02 = 0x02; - break; + } else { + areg_05 = 0x07; } nicam_flag = 1; break; /* other */ case 3: - switch (dev->norm) { - /* DK3_A2 */ - case V4L2_STD_DK: + if (dev->norm & V4L2_STD_DK) { areg_05 = 0x0b; - break; - /* Korea */ - case V4L2_STD_NTSC_M_KR: - areg_05 = 0x04; - break; - /* EIAJ */ - case V4L2_STD_NTSC_M_JP: - areg_05 = 0x03; - break; - default: + } else { areg_05 = 0x02; - break; } break; } @@ -557,10 +526,16 @@ int tm6000_set_standard(struct tm6000_core *dev) case TM6000_AMUX_ADC1: tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x00, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x10, 0xf0); break; case TM6000_AMUX_ADC2: tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x08, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x10, 0xf0); break; case TM6000_AMUX_SIF1: reg_08_e2 |= 0x02; @@ -570,6 +545,9 @@ int tm6000_set_standard(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x02, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x30, 0xf0); break; case TM6000_AMUX_SIF2: reg_08_e2 |= 0x02; @@ -579,6 +557,9 @@ int tm6000_set_standard(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf7); tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x02, 0x0f); + /* Mux overflow workaround */ + tm6000_set_reg_mask(dev, TM6010_REQ07_R07_OUTPUT_CONTROL, + 0x30, 0xf0); break; default: break; diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c index 1e5ace0b5d10..bc13db736e24 100644 --- a/drivers/media/video/tm6000/tm6000-video.c +++ b/drivers/media/video/tm6000/tm6000-video.c @@ -1605,16 +1605,25 @@ static int tm6000_release(struct file *file) res_free(dev, fh); if (!dev->users) { - int err; - tm6000_uninit_isoc(dev); + /* Stop interrupt USB pipe */ + tm6000_ir_int_stop(dev); + + usb_reset_configuration(dev->udev); + + if (dev->int_in.endp) + usb_set_interface(dev->udev, + dev->isoc_in.bInterfaceNumber, 2); + else + usb_set_interface(dev->udev, + dev->isoc_in.bInterfaceNumber, 0); + + /* Start interrupt USB pipe */ + tm6000_ir_int_start(dev); + if (!fh->radio) videobuf_mmap_free(&fh->vb_vidq); - - err = tm6000_reset(dev); - if (err < 0) - dev_err(&vdev->dev, "reset failed: %d\n", err); } kfree(fh); diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h index 2777e514eff2..27ba659cfa85 100644 --- a/drivers/media/video/tm6000/tm6000.h +++ b/drivers/media/video/tm6000/tm6000.h @@ -188,6 +188,9 @@ struct tm6000_core { /* Device Capabilities*/ struct tm6000_capabilities caps; + /* Used to load alsa/dvb */ + struct work_struct request_module_wk; + /* Tuner configuration */ int tuner_type; /* type of the tuner */ int tuner_addr; /* tuner address */ diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 11cc980b0cd5..4059ea178c2d 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -326,6 +326,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->mode_mask = T_RADIO; break; case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_PHILIPS_FMD1216MEX_MK3: buffer[0] = 0x0b; buffer[1] = 0xdc; buffer[2] = 0x9c; diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 926f03931156..dd26cacd0556 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -52,7 +52,7 @@ #define LOCK_RETRY_DELAY (200) /* Debug functions */ -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 6abaa16ae136..6be9910a6e24 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -703,21 +703,21 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) /* First tests should be against specific std */ if (std == V4L2_STD_ALL) { - fmt = 0; /* Autodetect mode */ + fmt = VIDEO_STD_AUTO_SWITCH_BIT; /* Autodetect mode */ } else if (std & V4L2_STD_NTSC_443) { - fmt = 0xa; + fmt = VIDEO_STD_NTSC_4_43_BIT; } else if (std & V4L2_STD_PAL_M) { - fmt = 0x6; + fmt = VIDEO_STD_PAL_M_BIT; } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) { - fmt = 0x8; + fmt = VIDEO_STD_PAL_COMBINATION_N_BIT; } else { /* Then, test against generic ones */ if (std & V4L2_STD_NTSC) - fmt = 0x2; + fmt = VIDEO_STD_NTSC_MJ_BIT; else if (std & V4L2_STD_PAL) - fmt = 0x4; + fmt = VIDEO_STD_PAL_BDGHIN_BIT; else if (std & V4L2_STD_SECAM) - fmt = 0xc; + fmt = VIDEO_STD_SECAM_BIT; } v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); @@ -779,6 +779,70 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) return -EINVAL; } +static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) +{ + int val = tvp5150_read(sd, TVP5150_STATUS_REG_5); + + switch (val & 0x0F) { + case 0x01: + return V4L2_STD_NTSC; + case 0x03: + return V4L2_STD_PAL; + case 0x05: + return V4L2_STD_PAL_M; + case 0x07: + return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc; + case 0x09: + return V4L2_STD_NTSC_443; + case 0xb: + return V4L2_STD_SECAM; + default: + return V4L2_STD_UNKNOWN; + } +} + +static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, + enum v4l2_mbus_pixelcode *code) +{ + if (index) + return -EINVAL; + + *code = V4L2_MBUS_FMT_YUYV8_2X8; + return 0; +} + +static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *f) +{ + struct tvp5150 *decoder = to_tvp5150(sd); + v4l2_std_id std; + + if (f == NULL) + return -EINVAL; + + tvp5150_reset(sd, 0); + + /* Calculate height and width based on current standard */ + if (decoder->norm == V4L2_STD_ALL) + std = tvp5150_read_std(sd); + else + std = decoder->norm; + + f->width = 720; + if (std & V4L2_STD_525_60) + f->height = 480; + else + f->height = 576; + + f->code = V4L2_MBUS_FMT_YUYV8_2X8; + f->field = V4L2_FIELD_SEQ_TB; + f->colorspace = V4L2_COLORSPACE_SMPTE170M; + + v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width, + f->height); + return 0; +} + /**************************************************************************** I2C Command ****************************************************************************/ @@ -931,6 +995,9 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_routing = tvp5150_s_routing, + .enum_mbus_fmt = tvp5150_enum_mbus_fmt, + .s_mbus_fmt = tvp5150_mbus_fmt, + .try_mbus_fmt = tvp5150_mbus_fmt, }; static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index 7875e80cb2ff..236c559d5f51 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -63,7 +63,7 @@ MODULE_LICENSE("GPL"); #define TVP7002_CL_MASK 0x0f /* Debug functions */ -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-2)"); diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 9bbe61700fd5..65d065aa6091 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -34,7 +34,7 @@ MODULE_DESCRIPTION("uPD64083 driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static bool debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index d7f97513b289..89fec029e924 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -110,42 +110,20 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, unsigned char addr; int ret; - if ((flags & I2C_M_TEN)) { - /* a ten bit address */ - addr = 0xf0 | ((msg->addr >> 7) & 0x03); - /* try extended address code... */ - ret = try_write_address(i2c_adap, addr, retries); - if (ret != 1) { - dev_err(&i2c_adap->dev, - "died at extended address code, while writing\n"); - return -EREMOTEIO; - } - add[0] = addr; - if (flags & I2C_M_RD) { - /* okay, now switch into reading mode */ - addr |= 0x01; - ret = try_read_address(i2c_adap, addr, retries); - if (ret != 1) { - dev_err(&i2c_adap->dev, - "died at extended address code, while reading\n"); - return -EREMOTEIO; - } - } - } else { /* normal 7bit address */ - addr = (msg->addr << 1); - if (flags & I2C_M_RD) - addr |= 1; + addr = (msg->addr << 1); + if (flags & I2C_M_RD) + addr |= 1; - add[0] = addr; - if (flags & I2C_M_RD) - ret = try_read_address(i2c_adap, addr, retries); - else - ret = try_write_address(i2c_adap, addr, retries); + add[0] = addr; + if (flags & I2C_M_RD) + ret = try_read_address(i2c_adap, addr, retries); + else + ret = try_write_address(i2c_adap, addr, retries); + + if (ret != 1) + return -EREMOTEIO; - if (ret != 1) - return -EREMOTEIO; - } return 0; } @@ -184,7 +162,7 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) static u32 functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } /* -----exported algorithm data: ------------------------------------- */ diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig index 2956a7637219..6c197da531b2 100644 --- a/drivers/media/video/uvc/Kconfig +++ b/drivers/media/video/uvc/Kconfig @@ -1,5 +1,6 @@ config USB_VIDEO_CLASS tristate "USB Video Class (UVC)" + select VIDEOBUF2_VMALLOC ---help--- Support for the USB Video Class (UVC). Currently only video input devices, such as webcams, are supported. diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile index 2071ca8a2f03..c26d12fdb8f4 100644 --- a/drivers/media/video/uvc/Makefile +++ b/drivers/media/video/uvc/Makefile @@ -1,5 +1,5 @@ uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ - uvc_status.o uvc_isight.o + uvc_status.o uvc_isight.o uvc_debugfs.o ifeq ($(CONFIG_MEDIA_CONTROLLER),y) uvcvideo-objs += uvc_entity.o endif diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 254d32688843..0efd3b10b353 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -878,8 +878,21 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, chain->dev->intfnum, ctrl->info.selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), ctrl->info.size); - if (ret < 0) - return ret; + if (ret < 0) { + if (UVC_ENTITY_TYPE(ctrl->entity) != + UVC_VC_EXTENSION_UNIT) + return ret; + + /* GET_RES is mandatory for XU controls, but some + * cameras still choke on it. Ignore errors and set the + * resolution value to zero. + */ + uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES, + "UVC non compliance - GET_RES failed on " + "an XU control. Enabling workaround.\n"); + memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0, + ctrl->info.size); + } } ctrl->cached = 1; @@ -1861,7 +1874,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) if (ncontrols == 0) continue; - entity->controls = kzalloc(ncontrols * sizeof(*ctrl), + entity->controls = kcalloc(ncontrols, sizeof(*ctrl), GFP_KERNEL); if (entity->controls == NULL) return -ENOMEM; diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c new file mode 100644 index 000000000000..14561a5abb79 --- /dev/null +++ b/drivers/media/video/uvc/uvc_debugfs.c @@ -0,0 +1,136 @@ +/* + * uvc_debugfs.c -- USB Video Class driver - Debugging support + * + * Copyright (C) 2011 + * Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * 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 <linux/module.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include "uvcvideo.h" + +/* ----------------------------------------------------------------------------- + * Statistics + */ + +#define UVC_DEBUGFS_BUF_SIZE 1024 + +struct uvc_debugfs_buffer { + size_t count; + char data[UVC_DEBUGFS_BUF_SIZE]; +}; + +static int uvc_debugfs_stats_open(struct inode *inode, struct file *file) +{ + struct uvc_streaming *stream = inode->i_private; + struct uvc_debugfs_buffer *buf; + + buf = kmalloc(sizeof(*buf), GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data)); + + file->private_data = buf; + return 0; +} + +static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf, + size_t nbytes, loff_t *ppos) +{ + struct uvc_debugfs_buffer *buf = file->private_data; + + return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data, + buf->count); +} + +static int uvc_debugfs_stats_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + file->private_data = NULL; + + return 0; +} + +static const struct file_operations uvc_debugfs_stats_fops = { + .owner = THIS_MODULE, + .open = uvc_debugfs_stats_open, + .llseek = no_llseek, + .read = uvc_debugfs_stats_read, + .release = uvc_debugfs_stats_release, +}; + +/* ----------------------------------------------------------------------------- + * Global and stream initialization/cleanup + */ + +static struct dentry *uvc_debugfs_root_dir; + +int uvc_debugfs_init_stream(struct uvc_streaming *stream) +{ + struct usb_device *udev = stream->dev->udev; + struct dentry *dent; + char dir_name[32]; + + if (uvc_debugfs_root_dir == NULL) + return -ENODEV; + + sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum); + + dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); + if (IS_ERR_OR_NULL(dent)) { + uvc_printk(KERN_INFO, "Unable to create debugfs %s " + "directory.\n", dir_name); + return -ENODEV; + } + + stream->debugfs_dir = dent; + + dent = debugfs_create_file("stats", 0444, stream->debugfs_dir, + stream, &uvc_debugfs_stats_fops); + if (IS_ERR_OR_NULL(dent)) { + uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n"); + uvc_debugfs_cleanup_stream(stream); + return -ENODEV; + } + + return 0; +} + +void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream) +{ + if (stream->debugfs_dir == NULL) + return; + + debugfs_remove_recursive(stream->debugfs_dir); + stream->debugfs_dir = NULL; +} + +int uvc_debugfs_init(void) +{ + struct dentry *dir; + + dir = debugfs_create_dir("uvcvideo", usb_debug_root); + if (IS_ERR_OR_NULL(dir)) { + uvc_printk(KERN_INFO, "Unable to create debugfs directory\n"); + return -ENODATA; + } + + uvc_debugfs_root_dir = dir; + return 0; +} + +void uvc_debugfs_cleanup(void) +{ + if (uvc_debugfs_root_dir != NULL) + debugfs_remove_recursive(uvc_debugfs_root_dir); +} diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 656d4c9e3b9f..a240d43d15d1 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1675,6 +1675,8 @@ static void uvc_unregister_video(struct uvc_device *dev) video_unregister_device(stream->vdev); stream->vdev = NULL; + + uvc_debugfs_cleanup_stream(stream); } /* Decrement the stream count and call uvc_delete explicitly if there @@ -1700,6 +1702,8 @@ static int uvc_register_video(struct uvc_device *dev, return ret; } + uvc_debugfs_init_stream(stream); + /* Register the device with V4L. */ vdev = video_device_alloc(); if (vdev == NULL) { @@ -2033,6 +2037,15 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); * though they are compliant. */ static struct usb_device_id uvc_ids[] = { + /* LogiLink Wireless Webcam */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0416, + .idProduct = 0xa91a, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Genius eFace 2025 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2396,17 +2409,24 @@ struct uvc_driver uvc_driver = { static int __init uvc_init(void) { - int result; + int ret; + + uvc_debugfs_init(); - result = usb_register(&uvc_driver.driver); - if (result == 0) - printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n"); - return result; + ret = usb_register(&uvc_driver.driver); + if (ret < 0) { + uvc_debugfs_cleanup(); + return ret; + } + + printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n"); + return 0; } static void __exit uvc_cleanup(void) { usb_deregister(&uvc_driver.driver); + uvc_debugfs_cleanup(); } module_init(uvc_init); diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c index 74bbe8f18f3e..8510e7259e76 100644 --- a/drivers/media/video/uvc/uvc_isight.c +++ b/drivers/media/video/uvc/uvc_isight.c @@ -74,7 +74,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, * Empty buffers (bytesused == 0) don't trigger end of frame detection * as it doesn't make sense to return an empty buffer. */ - if (is_header && buf->buf.bytesused != 0) { + if (is_header && buf->bytesused != 0) { buf->state = UVC_BUF_STATE_DONE; return -EAGAIN; } @@ -83,13 +83,13 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, * contain no data. */ if (!is_header) { - maxlen = buf->buf.length - buf->buf.bytesused; - mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; + maxlen = buf->length - buf->bytesused; + mem = buf->mem + buf->bytesused; nbytes = min(len, maxlen); memcpy(mem, data, nbytes); - buf->buf.bytesused += nbytes; + buf->bytesused += nbytes; - if (len > maxlen || buf->buf.bytesused == buf->buf.length) { + if (len > maxlen || buf->bytesused == buf->length) { uvc_trace(UVC_TRACE_FRAME, "Frame complete " "(overflow).\n"); buf->state = UVC_BUF_STATE_DONE; diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 677691c44500..518f77d3a4d8 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -11,6 +11,7 @@ * */ +#include <linux/atomic.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/list.h> @@ -19,7 +20,7 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <linux/atomic.h> +#include <media/videobuf2-vmalloc.h> #include "uvcvideo.h" @@ -29,467 +30,211 @@ * Video queues is initialized by uvc_queue_init(). The function performs * basic initialization of the uvc_video_queue struct and never fails. * - * Video buffer allocation and freeing are performed by uvc_alloc_buffers and - * uvc_free_buffers respectively. The former acquires the video queue lock, - * while the later must be called with the lock held (so that allocation can - * free previously allocated buffers). Trying to free buffers that are mapped - * to user space will return -EBUSY. - * - * Video buffers are managed using two queues. However, unlike most USB video - * drivers that use an in queue and an out queue, we use a main queue to hold - * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to - * hold empty buffers. This design (copied from video-buf) minimizes locking - * in interrupt, as only one queue is shared between interrupt and user - * contexts. - * - * Use cases - * --------- - * - * Unless stated otherwise, all operations that modify the irq buffers queue - * are protected by the irq spinlock. - * - * 1. The user queues the buffers, starts streaming and dequeues a buffer. - * - * The buffers are added to the main and irq queues. Both operations are - * protected by the queue lock, and the later is protected by the irq - * spinlock as well. - * - * The completion handler fetches a buffer from the irq queue and fills it - * with video data. If no buffer is available (irq queue empty), the handler - * returns immediately. - * - * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue. - * At that point, any process waiting on the buffer will be woken up. If a - * process tries to dequeue a buffer after it has been marked done, the - * dequeing will succeed immediately. - * - * 2. Buffers are queued, user is waiting on a buffer and the device gets - * disconnected. - * - * When the device is disconnected, the kernel calls the completion handler - * with an appropriate status code. The handler marks all buffers in the - * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so - * that any process waiting on a buffer gets woken up. - * - * Waking up up the first buffer on the irq list is not enough, as the - * process waiting on the buffer might restart the dequeue operation - * immediately. - * + * Video buffers are managed by videobuf2. The driver uses a mutex to protect + * the videobuf2 queue operations by serializing calls to videobuf2 and a + * spinlock to protect the IRQ queue that holds the buffers to be processed by + * the driver. */ -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, - int drop_corrupted) -{ - mutex_init(&queue->mutex); - spin_lock_init(&queue->irqlock); - INIT_LIST_HEAD(&queue->mainqueue); - INIT_LIST_HEAD(&queue->irqqueue); - queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; - queue->type = type; -} - -/* - * Free the video buffers. - * - * This function must be called with the queue lock held. +/* ----------------------------------------------------------------------------- + * videobuf2 queue operations */ -static int __uvc_free_buffers(struct uvc_video_queue *queue) + +static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - unsigned int i; + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + struct uvc_streaming *stream = + container_of(queue, struct uvc_streaming, queue); - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } + if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) + *nbuffers = UVC_MAX_VIDEO_BUFFERS; - if (queue->count) { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); - vfree(queue->mem); - queue->count = 0; - } + *nplanes = 1; + + sizes[0] = stream->ctrl.dwMaxVideoFrameSize; return 0; } -int uvc_free_buffers(struct uvc_video_queue *queue) +static int uvc_buffer_prepare(struct vb2_buffer *vb) { - int ret; + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - mutex_lock(&queue->mutex); - ret = __uvc_free_buffers(queue); - mutex_unlock(&queue->mutex); + if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { + uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); + return -EINVAL; + } - return ret; -} + if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED)) + return -ENODEV; -/* - * Allocate the video buffers. - * - * Pages are reserved to make sure they will not be swapped, as they will be - * filled in the URB completion handler. - * - * Buffers will be individually mapped, so they must all be page aligned. - */ -int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, - unsigned int buflength) -{ - unsigned int bufsize = PAGE_ALIGN(buflength); - unsigned int i; - void *mem = NULL; - int ret; + buf->state = UVC_BUF_STATE_QUEUED; + buf->error = 0; + buf->mem = vb2_plane_vaddr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + buf->bytesused = 0; + else + buf->bytesused = vb2_get_plane_payload(vb, 0); - if (nbuffers > UVC_MAX_VIDEO_BUFFERS) - nbuffers = UVC_MAX_VIDEO_BUFFERS; + return 0; +} - mutex_lock(&queue->mutex); +static void uvc_buffer_queue(struct vb2_buffer *vb) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); + unsigned long flags; - if ((ret = __uvc_free_buffers(queue)) < 0) - goto done; + spin_lock_irqsave(&queue->irqlock, flags); + if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) { + list_add_tail(&buf->queue, &queue->irqqueue); + } else { + /* If the device is disconnected return the buffer to userspace + * directly. The next QBUF call will fail with -ENODEV. + */ + buf->state = UVC_BUF_STATE_ERROR; + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); + } - /* Bail out if no buffers should be allocated. */ - if (nbuffers == 0) - goto done; + spin_unlock_irqrestore(&queue->irqlock, flags); +} - /* Decrement the number of buffers until allocation succeeds. */ - for (; nbuffers > 0; --nbuffers) { - mem = vmalloc_32(nbuffers * bufsize); - if (mem != NULL) - break; - } +static int uvc_buffer_finish(struct vb2_buffer *vb) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_streaming *stream = + container_of(queue, struct uvc_streaming, queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - if (mem == NULL) { - ret = -ENOMEM; - goto done; - } + uvc_video_clock_update(stream, &vb->v4l2_buf, buf); + return 0; +} - for (i = 0; i < nbuffers; ++i) { - memset(&queue->buffer[i], 0, sizeof queue->buffer[i]); - queue->buffer[i].buf.index = i; - queue->buffer[i].buf.m.offset = i * bufsize; - queue->buffer[i].buf.length = buflength; - queue->buffer[i].buf.type = queue->type; - queue->buffer[i].buf.field = V4L2_FIELD_NONE; - queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; - queue->buffer[i].buf.flags = 0; - init_waitqueue_head(&queue->buffer[i].wait); - } +static struct vb2_ops uvc_queue_qops = { + .queue_setup = uvc_queue_setup, + .buf_prepare = uvc_buffer_prepare, + .buf_queue = uvc_buffer_queue, + .buf_finish = uvc_buffer_finish, +}; - queue->mem = mem; - queue->count = nbuffers; - queue->buf_size = bufsize; - ret = nbuffers; +void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + int drop_corrupted) +{ + queue->queue.type = type; + queue->queue.io_modes = VB2_MMAP; + queue->queue.drv_priv = queue; + queue->queue.buf_struct_size = sizeof(struct uvc_buffer); + queue->queue.ops = &uvc_queue_qops; + queue->queue.mem_ops = &vb2_vmalloc_memops; + vb2_queue_init(&queue->queue); -done: - mutex_unlock(&queue->mutex); - return ret; + mutex_init(&queue->mutex); + spin_lock_init(&queue->irqlock); + INIT_LIST_HEAD(&queue->irqqueue); + queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; } -/* - * Check if buffers have been allocated. +/* ----------------------------------------------------------------------------- + * V4L2 queue operations */ -int uvc_queue_allocated(struct uvc_video_queue *queue) + +int uvc_alloc_buffers(struct uvc_video_queue *queue, + struct v4l2_requestbuffers *rb) { - int allocated; + int ret; mutex_lock(&queue->mutex); - allocated = queue->count != 0; + ret = vb2_reqbufs(&queue->queue, rb); mutex_unlock(&queue->mutex); - return allocated; + return ret ? ret : rb->count; } -static void __uvc_query_buffer(struct uvc_buffer *buf, - struct v4l2_buffer *v4l2_buf) +void uvc_free_buffers(struct uvc_video_queue *queue) { - memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); - - if (buf->vma_use_count) - v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - case UVC_BUF_STATE_DONE: - v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; - break; - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - case UVC_BUF_STATE_READY: - v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case UVC_BUF_STATE_IDLE: - default: - break; - } + mutex_lock(&queue->mutex); + vb2_queue_release(&queue->queue); + mutex_unlock(&queue->mutex); } -int uvc_query_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) +int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { - int ret = 0; + int ret; mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - ret = -EINVAL; - goto done; - } - - __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf); - -done: + ret = vb2_querybuf(&queue->queue, buf); mutex_unlock(&queue->mutex); + return ret; } -/* - * Queue a video buffer. Attempting to queue a buffer that has already been - * queued will return -EINVAL. - */ -int uvc_queue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf) +int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { - struct uvc_buffer *buf; - unsigned long flags; - int ret = 0; - - uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } + int ret; mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n"); - ret = -EINVAL; - goto done; - } - - buf = &queue->buffer[v4l2_buf->index]; - if (buf->state != UVC_BUF_STATE_IDLE) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state " - "(%u).\n", buf->state); - ret = -EINVAL; - goto done; - } - - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - v4l2_buf->bytesused > buf->buf.length) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); - ret = -EINVAL; - goto done; - } - - spin_lock_irqsave(&queue->irqlock, flags); - if (queue->flags & UVC_QUEUE_DISCONNECTED) { - spin_unlock_irqrestore(&queue->irqlock, flags); - ret = -ENODEV; - goto done; - } - buf->state = UVC_BUF_STATE_QUEUED; - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - buf->buf.bytesused = 0; - else - buf->buf.bytesused = v4l2_buf->bytesused; - - list_add_tail(&buf->stream, &queue->mainqueue); - list_add_tail(&buf->queue, &queue->irqqueue); - spin_unlock_irqrestore(&queue->irqlock, flags); - -done: + ret = vb2_qbuf(&queue->queue, buf); mutex_unlock(&queue->mutex); - return ret; -} -static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE && - buf->state != UVC_BUF_STATE_READY) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE && - buf->state != UVC_BUF_STATE_READY); + return ret; } -/* - * Dequeue a video buffer. If nonblocking is false, block until a buffer is - * available. - */ -int uvc_dequeue_buffer(struct uvc_video_queue *queue, - struct v4l2_buffer *v4l2_buf, int nonblocking) +int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, + int nonblocking) { - struct uvc_buffer *buf; - int ret = 0; - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } + int ret; mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n"); - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0) - goto done; - - uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n", - buf->buf.index, buf->state, buf->buf.bytesused); - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data " - "(transmission error).\n"); - ret = -EIO; - case UVC_BUF_STATE_DONE: - buf->state = UVC_BUF_STATE_IDLE; - break; - - case UVC_BUF_STATE_IDLE: - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - case UVC_BUF_STATE_READY: - default: - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u " - "(driver bug?).\n", buf->state); - ret = -EINVAL; - goto done; - } - - list_del(&buf->stream); - __uvc_query_buffer(buf, v4l2_buf); - -done: + ret = vb2_dqbuf(&queue->queue, buf, nonblocking); mutex_unlock(&queue->mutex); - return ret; -} -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; -} - -static void uvc_vm_close(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; + return ret; } -static const struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; - -/* - * Memory-map a video buffer. - * - * This function implements video buffers memory mapping and is intended to be - * used by the device mmap handler. - */ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) { - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; - - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; + int ret; mutex_lock(&queue->mutex); + ret = vb2_mmap(&queue->queue, vma); + mutex_unlock(&queue->mutex); - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; -#ifdef CONFIG_MMU - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } -#endif + return ret; +} - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); +unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, + poll_table *wait) +{ + unsigned int ret; -done: + mutex_lock(&queue->mutex); + ret = vb2_poll(&queue->queue, file, wait); mutex_unlock(&queue->mutex); + return ret; } -/* - * Poll the video queue. +/* ----------------------------------------------------------------------------- * - * This function implements video queue polling and is intended to be used by - * the device poll handler. */ -unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) + +/* + * Check if buffers have been allocated. + */ +int uvc_queue_allocated(struct uvc_video_queue *queue) { - struct uvc_buffer *buf; - unsigned int mask = 0; + int allocated; mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - mask |= POLLERR; - goto done; - } - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) { - if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - mask |= POLLIN | POLLRDNORM; - else - mask |= POLLOUT | POLLWRNORM; - } - -done: + allocated = vb2_is_busy(&queue->queue); mutex_unlock(&queue->mutex); - return mask; + + return allocated; } #ifndef CONFIG_MMU @@ -515,7 +260,7 @@ unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, ret = -EINVAL; goto done; } - ret = (unsigned long)queue->mem + buffer->buf.m.offset; + ret = (unsigned long)buf->mem; done: mutex_unlock(&queue->mutex); return ret; @@ -540,27 +285,24 @@ done: */ int uvc_queue_enable(struct uvc_video_queue *queue, int enable) { - unsigned int i; - int ret = 0; + unsigned long flags; + int ret; mutex_lock(&queue->mutex); if (enable) { - if (uvc_queue_streaming(queue)) { - ret = -EBUSY; + ret = vb2_streamon(&queue->queue, queue->queue.type); + if (ret < 0) goto done; - } - queue->flags |= UVC_QUEUE_STREAMING; + queue->buf_used = 0; } else { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); - - for (i = 0; i < queue->count; ++i) { - queue->buffer[i].error = 0; - queue->buffer[i].state = UVC_BUF_STATE_IDLE; - } + ret = vb2_streamoff(&queue->queue, queue->queue.type); + if (ret < 0) + goto done; - queue->flags &= ~UVC_QUEUE_STREAMING; + spin_lock_irqsave(&queue->irqlock, flags); + INIT_LIST_HEAD(&queue->irqqueue); + spin_unlock_irqrestore(&queue->irqlock, flags); } done: @@ -591,12 +333,12 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) queue); list_del(&buf->queue); buf->state = UVC_BUF_STATE_ERROR; - wake_up(&buf->wait); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); } /* This must be protected by the irqlock spinlock to avoid race - * conditions between uvc_queue_buffer and the disconnection event that + * conditions between uvc_buffer_queue and the disconnection event that * could result in an interruptible wait in uvc_dequeue_buffer. Do not - * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED + * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED * state outside the queue code. */ if (disconnect) @@ -613,14 +355,12 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { buf->error = 0; buf->state = UVC_BUF_STATE_QUEUED; - buf->buf.bytesused = 0; + vb2_set_plane_payload(&buf->buf, 0, 0); return buf; } spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); - buf->error = 0; - buf->state = UVC_BUF_STATE_DONE; if (!list_empty(&queue->irqqueue)) nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, queue); @@ -628,7 +368,9 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, nextbuf = NULL; spin_unlock_irqrestore(&queue->irqlock, flags); - wake_up(&buf->wait); + buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; + vb2_set_plane_payload(&buf->buf, 0, buf->bytesused); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); + return nextbuf; } - diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index dadf11f704dc..2ae4f880ea05 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -58,6 +58,15 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, break; case V4L2_CTRL_TYPE_MENU: + /* Prevent excessive memory consumption, as well as integer + * overflows. + */ + if (xmap->menu_count == 0 || + xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) { + ret = -EINVAL; + goto done; + } + size = xmap->menu_count * sizeof(*map->menu_info); map->menu_info = kmalloc(size, GFP_KERNEL); if (map->menu_info == NULL) { @@ -513,10 +522,7 @@ static int uvc_v4l2_release(struct file *file) /* Only free resources if this is a privileged handle. */ if (uvc_has_privileges(handle)) { uvc_video_enable(stream, 0); - - if (uvc_free_buffers(&stream->queue) < 0) - uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " - "free buffers.\n"); + uvc_free_buffers(&stream->queue); } /* Release the file handle. */ @@ -914,19 +920,11 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) /* Buffers & streaming */ case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - - if (rb->type != stream->type || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; mutex_lock(&stream->mutex); - ret = uvc_alloc_buffers(&stream->queue, rb->count, - stream->ctrl.dwMaxVideoFrameSize); + ret = uvc_alloc_buffers(&stream->queue, arg); mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -934,18 +932,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (ret == 0) uvc_dismiss_privileges(handle); - rb->count = ret; ret = 0; break; - } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; - if (buf->type != stream->type) - return -EINVAL; - if (!uvc_has_privileges(handle)) return -EBUSY; diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index b015e8e5e8b0..c7e69b8f81c9 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -351,25 +351,553 @@ done: return ret; } -int uvc_commit_video(struct uvc_streaming *stream, - struct uvc_streaming_control *probe) +static int uvc_commit_video(struct uvc_streaming *stream, + struct uvc_streaming_control *probe) { return uvc_set_video_ctrl(stream, probe, 0); } +/* ----------------------------------------------------------------------------- + * Clocks and timestamps + */ + +static void +uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, + const __u8 *data, int len) +{ + struct uvc_clock_sample *sample; + unsigned int header_size; + bool has_pts = false; + bool has_scr = false; + unsigned long flags; + struct timespec ts; + u16 host_sof; + u16 dev_sof; + + switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { + case UVC_STREAM_PTS | UVC_STREAM_SCR: + header_size = 12; + has_pts = true; + has_scr = true; + break; + case UVC_STREAM_PTS: + header_size = 6; + has_pts = true; + break; + case UVC_STREAM_SCR: + header_size = 8; + has_scr = true; + break; + default: + header_size = 2; + break; + } + + /* Check for invalid headers. */ + if (len < header_size) + return; + + /* Extract the timestamps: + * + * - store the frame PTS in the buffer structure + * - if the SCR field is present, retrieve the host SOF counter and + * kernel timestamps and store them with the SCR STC and SOF fields + * in the ring buffer + */ + if (has_pts && buf != NULL) + buf->pts = get_unaligned_le32(&data[2]); + + if (!has_scr) + return; + + /* To limit the amount of data, drop SCRs with an SOF identical to the + * previous one. + */ + dev_sof = get_unaligned_le16(&data[header_size - 2]); + if (dev_sof == stream->clock.last_sof) + return; + + stream->clock.last_sof = dev_sof; + + host_sof = usb_get_current_frame_number(stream->dev->udev); + ktime_get_ts(&ts); + + /* The UVC specification allows device implementations that can't obtain + * the USB frame number to keep their own frame counters as long as they + * match the size and frequency of the frame number associated with USB + * SOF tokens. The SOF values sent by such devices differ from the USB + * SOF tokens by a fixed offset that needs to be estimated and accounted + * for to make timestamp recovery as accurate as possible. + * + * The offset is estimated the first time a device SOF value is received + * as the difference between the host and device SOF values. As the two + * SOF values can differ slightly due to transmission delays, consider + * that the offset is null if the difference is not higher than 10 ms + * (negative differences can not happen and are thus considered as an + * offset). The video commit control wDelay field should be used to + * compute a dynamic threshold instead of using a fixed 10 ms value, but + * devices don't report reliable wDelay values. + * + * See uvc_video_clock_host_sof() for an explanation regarding why only + * the 8 LSBs of the delta are kept. + */ + if (stream->clock.sof_offset == (u16)-1) { + u16 delta_sof = (host_sof - dev_sof) & 255; + if (delta_sof >= 10) + stream->clock.sof_offset = delta_sof; + else + stream->clock.sof_offset = 0; + } + + dev_sof = (dev_sof + stream->clock.sof_offset) & 2047; + + spin_lock_irqsave(&stream->clock.lock, flags); + + sample = &stream->clock.samples[stream->clock.head]; + sample->dev_stc = get_unaligned_le32(&data[header_size - 6]); + sample->dev_sof = dev_sof; + sample->host_sof = host_sof; + sample->host_ts = ts; + + /* Update the sliding window head and count. */ + stream->clock.head = (stream->clock.head + 1) % stream->clock.size; + + if (stream->clock.count < stream->clock.size) + stream->clock.count++; + + spin_unlock_irqrestore(&stream->clock.lock, flags); +} + +static int uvc_video_clock_init(struct uvc_streaming *stream) +{ + struct uvc_clock *clock = &stream->clock; + + spin_lock_init(&clock->lock); + clock->head = 0; + clock->count = 0; + clock->size = 32; + clock->last_sof = -1; + clock->sof_offset = -1; + + clock->samples = kmalloc(clock->size * sizeof(*clock->samples), + GFP_KERNEL); + if (clock->samples == NULL) + return -ENOMEM; + + return 0; +} + +static void uvc_video_clock_cleanup(struct uvc_streaming *stream) +{ + kfree(stream->clock.samples); + stream->clock.samples = NULL; +} + +/* + * uvc_video_clock_host_sof - Return the host SOF value for a clock sample + * + * Host SOF counters reported by usb_get_current_frame_number() usually don't + * cover the whole 11-bits SOF range (0-2047) but are limited to the HCI frame + * schedule window. They can be limited to 8, 9 or 10 bits depending on the host + * controller and its configuration. + * + * We thus need to recover the SOF value corresponding to the host frame number. + * As the device and host frame numbers are sampled in a short interval, the + * difference between their values should be equal to a small delta plus an + * integer multiple of 256 caused by the host frame number limited precision. + * + * To obtain the recovered host SOF value, compute the small delta by masking + * the high bits of the host frame counter and device SOF difference and add it + * to the device SOF value. + */ +static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample) +{ + /* The delta value can be negative. */ + s8 delta_sof; + + delta_sof = (sample->host_sof - sample->dev_sof) & 255; + + return (sample->dev_sof + delta_sof) & 2047; +} + +/* + * uvc_video_clock_update - Update the buffer timestamp + * + * This function converts the buffer PTS timestamp to the host clock domain by + * going through the USB SOF clock domain and stores the result in the V4L2 + * buffer timestamp field. + * + * The relationship between the device clock and the host clock isn't known. + * However, the device and the host share the common USB SOF clock which can be + * used to recover that relationship. + * + * The relationship between the device clock and the USB SOF clock is considered + * to be linear over the clock samples sliding window and is given by + * + * SOF = m * PTS + p + * + * Several methods to compute the slope (m) and intercept (p) can be used. As + * the clock drift should be small compared to the sliding window size, we + * assume that the line that goes through the points at both ends of the window + * is a good approximation. Naming those points P1 and P2, we get + * + * SOF = (SOF2 - SOF1) / (STC2 - STC1) * PTS + * + (SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) + * + * or + * + * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) (1) + * + * to avoid loosing precision in the division. Similarly, the host timestamp is + * computed with + * + * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2) + * + * SOF values are coded on 11 bits by USB. We extend their precision with 16 + * decimal bits, leading to a 11.16 coding. + * + * TODO: To avoid surprises with device clock values, PTS/STC timestamps should + * be normalized using the nominal device clock frequency reported through the + * UVC descriptors. + * + * Both the PTS/STC and SOF counters roll over, after a fixed but device + * specific amount of time for PTS/STC and after 2048ms for SOF. As long as the + * sliding window size is smaller than the rollover period, differences computed + * on unsigned integers will produce the correct result. However, the p term in + * the linear relations will be miscomputed. + * + * To fix the issue, we subtract a constant from the PTS and STC values to bring + * PTS to half the 32 bit STC range. The sliding window STC values then fit into + * the 32 bit range without any rollover. + * + * Similarly, we add 2048 to the device SOF values to make sure that the SOF + * computed by (1) will never be smaller than 0. This offset is then compensated + * by adding 2048 to the SOF values used in (2). However, this doesn't prevent + * rollovers between (1) and (2): the SOF value computed by (1) can be slightly + * lower than 4096, and the host SOF counters can have rolled over to 2048. This + * case is handled by subtracting 2048 from the SOF value if it exceeds the host + * SOF value at the end of the sliding window. + * + * Finally we subtract a constant from the host timestamps to bring the first + * timestamp of the sliding window to 1s. + */ +void uvc_video_clock_update(struct uvc_streaming *stream, + struct v4l2_buffer *v4l2_buf, + struct uvc_buffer *buf) +{ + struct uvc_clock *clock = &stream->clock; + struct uvc_clock_sample *first; + struct uvc_clock_sample *last; + unsigned long flags; + struct timespec ts; + u32 delta_stc; + u32 y1, y2; + u32 x1, x2; + u32 mean; + u32 sof; + u32 div; + u32 rem; + u64 y; + + spin_lock_irqsave(&clock->lock, flags); + + if (clock->count < clock->size) + goto done; + + first = &clock->samples[clock->head]; + last = &clock->samples[(clock->head - 1) % clock->size]; + + /* First step, PTS to SOF conversion. */ + delta_stc = buf->pts - (1UL << 31); + x1 = first->dev_stc - delta_stc; + x2 = last->dev_stc - delta_stc; + y1 = (first->dev_sof + 2048) << 16; + y2 = (last->dev_sof + 2048) << 16; + + if (y2 < y1) + y2 += 2048 << 16; + + y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2 + - (u64)y2 * (u64)x1; + y = div_u64(y, x2 - x1); + + sof = y; + + uvc_trace(UVC_TRACE_CLOCK, "%s: PTS %u y %llu.%06llu SOF %u.%06llu " + "(x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n", + stream->dev->name, buf->pts, + y >> 16, div_u64((y & 0xffff) * 1000000, 65536), + sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), + x1, x2, y1, y2, clock->sof_offset); + + /* Second step, SOF to host clock conversion. */ + ts = timespec_sub(last->host_ts, first->host_ts); + x1 = (uvc_video_clock_host_sof(first) + 2048) << 16; + x2 = (uvc_video_clock_host_sof(last) + 2048) << 16; + y1 = NSEC_PER_SEC; + y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec; + + if (x2 < x1) + x2 += 2048 << 16; + + /* Interpolated and host SOF timestamps can wrap around at slightly + * different times. Handle this by adding or removing 2048 to or from + * the computed SOF value to keep it close to the SOF samples mean + * value. + */ + mean = (x1 + x2) / 2; + if (mean - (1024 << 16) > sof) + sof += 2048 << 16; + else if (sof > mean + (1024 << 16)) + sof -= 2048 << 16; + + y = (u64)(y2 - y1) * (u64)sof + (u64)y1 * (u64)x2 + - (u64)y2 * (u64)x1; + y = div_u64(y, x2 - x1); + + div = div_u64_rem(y, NSEC_PER_SEC, &rem); + ts.tv_sec = first->host_ts.tv_sec - 1 + div; + ts.tv_nsec = first->host_ts.tv_nsec + rem; + if (ts.tv_nsec >= NSEC_PER_SEC) { + ts.tv_sec++; + ts.tv_nsec -= NSEC_PER_SEC; + } + + uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu " + "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n", + stream->dev->name, + sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), + y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC, + v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec, + x1, first->host_sof, first->dev_sof, + x2, last->host_sof, last->dev_sof, y1, y2); + + /* Update the V4L2 buffer. */ + v4l2_buf->timestamp.tv_sec = ts.tv_sec; + v4l2_buf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + +done: + spin_unlock_irqrestore(&stream->clock.lock, flags); +} + /* ------------------------------------------------------------------------ - * Video codecs + * Stream statistics */ -/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ -#define UVC_STREAM_EOH (1 << 7) -#define UVC_STREAM_ERR (1 << 6) -#define UVC_STREAM_STI (1 << 5) -#define UVC_STREAM_RES (1 << 4) -#define UVC_STREAM_SCR (1 << 3) -#define UVC_STREAM_PTS (1 << 2) -#define UVC_STREAM_EOF (1 << 1) -#define UVC_STREAM_FID (1 << 0) +static void uvc_video_stats_decode(struct uvc_streaming *stream, + const __u8 *data, int len) +{ + unsigned int header_size; + bool has_pts = false; + bool has_scr = false; + u16 uninitialized_var(scr_sof); + u32 uninitialized_var(scr_stc); + u32 uninitialized_var(pts); + + if (stream->stats.stream.nb_frames == 0 && + stream->stats.frame.nb_packets == 0) + ktime_get_ts(&stream->stats.stream.start_ts); + + switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { + case UVC_STREAM_PTS | UVC_STREAM_SCR: + header_size = 12; + has_pts = true; + has_scr = true; + break; + case UVC_STREAM_PTS: + header_size = 6; + has_pts = true; + break; + case UVC_STREAM_SCR: + header_size = 8; + has_scr = true; + break; + default: + header_size = 2; + break; + } + + /* Check for invalid headers. */ + if (len < header_size || data[0] < header_size) { + stream->stats.frame.nb_invalid++; + return; + } + + /* Extract the timestamps. */ + if (has_pts) + pts = get_unaligned_le32(&data[2]); + + if (has_scr) { + scr_stc = get_unaligned_le32(&data[header_size - 6]); + scr_sof = get_unaligned_le16(&data[header_size - 2]); + } + + /* Is PTS constant through the whole frame ? */ + if (has_pts && stream->stats.frame.nb_pts) { + if (stream->stats.frame.pts != pts) { + stream->stats.frame.nb_pts_diffs++; + stream->stats.frame.last_pts_diff = + stream->stats.frame.nb_packets; + } + } + + if (has_pts) { + stream->stats.frame.nb_pts++; + stream->stats.frame.pts = pts; + } + + /* Do all frames have a PTS in their first non-empty packet, or before + * their first empty packet ? + */ + if (stream->stats.frame.size == 0) { + if (len > header_size) + stream->stats.frame.has_initial_pts = has_pts; + if (len == header_size && has_pts) + stream->stats.frame.has_early_pts = true; + } + + /* Do the SCR.STC and SCR.SOF fields vary through the frame ? */ + if (has_scr && stream->stats.frame.nb_scr) { + if (stream->stats.frame.scr_stc != scr_stc) + stream->stats.frame.nb_scr_diffs++; + } + + if (has_scr) { + /* Expand the SOF counter to 32 bits and store its value. */ + if (stream->stats.stream.nb_frames > 0 || + stream->stats.frame.nb_scr > 0) + stream->stats.stream.scr_sof_count += + (scr_sof - stream->stats.stream.scr_sof) % 2048; + stream->stats.stream.scr_sof = scr_sof; + + stream->stats.frame.nb_scr++; + stream->stats.frame.scr_stc = scr_stc; + stream->stats.frame.scr_sof = scr_sof; + + if (scr_sof < stream->stats.stream.min_sof) + stream->stats.stream.min_sof = scr_sof; + if (scr_sof > stream->stats.stream.max_sof) + stream->stats.stream.max_sof = scr_sof; + } + + /* Record the first non-empty packet number. */ + if (stream->stats.frame.size == 0 && len > header_size) + stream->stats.frame.first_data = stream->stats.frame.nb_packets; + + /* Update the frame size. */ + stream->stats.frame.size += len - header_size; + + /* Update the packets counters. */ + stream->stats.frame.nb_packets++; + if (len > header_size) + stream->stats.frame.nb_empty++; + + if (data[1] & UVC_STREAM_ERR) + stream->stats.frame.nb_errors++; +} + +static void uvc_video_stats_update(struct uvc_streaming *stream) +{ + struct uvc_stats_frame *frame = &stream->stats.frame; + + uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets, " + "%u/%u/%u pts (%searly %sinitial), %u/%u scr, " + "last pts/stc/sof %u/%u/%u\n", + stream->sequence, frame->first_data, + frame->nb_packets - frame->nb_empty, frame->nb_packets, + frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts, + frame->has_early_pts ? "" : "!", + frame->has_initial_pts ? "" : "!", + frame->nb_scr_diffs, frame->nb_scr, + frame->pts, frame->scr_stc, frame->scr_sof); + + stream->stats.stream.nb_frames++; + stream->stats.stream.nb_packets += stream->stats.frame.nb_packets; + stream->stats.stream.nb_empty += stream->stats.frame.nb_empty; + stream->stats.stream.nb_errors += stream->stats.frame.nb_errors; + stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid; + + if (frame->has_early_pts) + stream->stats.stream.nb_pts_early++; + if (frame->has_initial_pts) + stream->stats.stream.nb_pts_initial++; + if (frame->last_pts_diff <= frame->first_data) + stream->stats.stream.nb_pts_constant++; + if (frame->nb_scr >= frame->nb_packets - frame->nb_empty) + stream->stats.stream.nb_scr_count_ok++; + if (frame->nb_scr_diffs + 1 == frame->nb_scr) + stream->stats.stream.nb_scr_diffs_ok++; + + memset(&stream->stats.frame, 0, sizeof(stream->stats.frame)); +} + +size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, + size_t size) +{ + unsigned int scr_sof_freq; + unsigned int duration; + struct timespec ts; + size_t count = 0; + + ts.tv_sec = stream->stats.stream.stop_ts.tv_sec + - stream->stats.stream.start_ts.tv_sec; + ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec + - stream->stats.stream.start_ts.tv_nsec; + if (ts.tv_nsec < 0) { + ts.tv_sec--; + ts.tv_nsec += 1000000000; + } + + /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF + * frequency this will not overflow before more than 1h. + */ + duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + if (duration != 0) + scr_sof_freq = stream->stats.stream.scr_sof_count * 1000 + / duration; + else + scr_sof_freq = 0; + + count += scnprintf(buf + count, size - count, + "frames: %u\npackets: %u\nempty: %u\n" + "errors: %u\ninvalid: %u\n", + stream->stats.stream.nb_frames, + stream->stats.stream.nb_packets, + stream->stats.stream.nb_empty, + stream->stats.stream.nb_errors, + stream->stats.stream.nb_invalid); + count += scnprintf(buf + count, size - count, + "pts: %u early, %u initial, %u ok\n", + stream->stats.stream.nb_pts_early, + stream->stats.stream.nb_pts_initial, + stream->stats.stream.nb_pts_constant); + count += scnprintf(buf + count, size - count, + "scr: %u count ok, %u diff ok\n", + stream->stats.stream.nb_scr_count_ok, + stream->stats.stream.nb_scr_diffs_ok); + count += scnprintf(buf + count, size - count, + "sof: %u <= sof <= %u, freq %u.%03u kHz\n", + stream->stats.stream.min_sof, + stream->stats.stream.max_sof, + scr_sof_freq / 1000, scr_sof_freq % 1000); + + return count; +} + +static void uvc_video_stats_start(struct uvc_streaming *stream) +{ + memset(&stream->stats, 0, sizeof(stream->stats)); + stream->stats.stream.min_sof = 2048; +} + +static void uvc_video_stats_stop(struct uvc_streaming *stream) +{ + ktime_get_ts(&stream->stats.stream.stop_ts); +} + +/* ------------------------------------------------------------------------ + * Video codecs + */ /* Video payload decoding is handled by uvc_video_decode_start(), * uvc_video_decode_data() and uvc_video_decode_end(). @@ -416,14 +944,9 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, * - bHeaderLength value must be at least 2 bytes (see above) * - bHeaderLength value can't be larger than the packet size. */ - if (len < 2 || data[0] < 2 || data[0] > len) + if (len < 2 || data[0] < 2 || data[0] > len) { + stream->stats.frame.nb_invalid++; return -EINVAL; - - /* Skip payloads marked with the error bit ("error frames"). */ - if (data[1] & UVC_STREAM_ERR) { - uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit " - "set).\n"); - return -ENODATA; } fid = data[1] & UVC_STREAM_FID; @@ -431,8 +954,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, /* Increase the sequence number regardless of any buffer states, so * that discontinuous sequence numbers always indicate lost frames. */ - if (stream->last_fid != fid) + if (stream->last_fid != fid) { stream->sequence++; + if (stream->sequence) + uvc_video_stats_update(stream); + } + + uvc_video_clock_decode(stream, buf, data, len); + uvc_video_stats_decode(stream, data, len); /* Store the payload FID bit and return immediately when the buffer is * NULL. @@ -442,6 +971,13 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return -ENODATA; } + /* Mark the buffer as bad if the error bit is set. */ + if (data[1] & UVC_STREAM_ERR) { + uvc_trace(UVC_TRACE_FRAME, "Marking buffer as bad (error bit " + "set).\n"); + buf->error = 1; + } + /* Synchronize to the input stream by waiting for the FID bit to be * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. * stream->last_fid is initialized to -1, so the first isochronous @@ -467,9 +1003,10 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, else ktime_get_real_ts(&ts); - buf->buf.sequence = stream->sequence; - buf->buf.timestamp.tv_sec = ts.tv_sec; - buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + buf->buf.v4l2_buf.sequence = stream->sequence; + buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec; + buf->buf.v4l2_buf.timestamp.tv_usec = + ts.tv_nsec / NSEC_PER_USEC; /* TODO: Handle PTS and SCR. */ buf->state = UVC_BUF_STATE_ACTIVE; @@ -490,7 +1027,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, * avoids detecting end of frame conditions at FID toggling if the * previous payload had the EOF bit set. */ - if (fid != stream->last_fid && buf->buf.bytesused != 0) { + if (fid != stream->last_fid && buf->bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " "toggled).\n"); buf->state = UVC_BUF_STATE_READY; @@ -505,7 +1042,6 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, static void uvc_video_decode_data(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { - struct uvc_video_queue *queue = &stream->queue; unsigned int maxlen, nbytes; void *mem; @@ -513,11 +1049,11 @@ static void uvc_video_decode_data(struct uvc_streaming *stream, return; /* Copy the video data to the buffer. */ - maxlen = buf->buf.length - buf->buf.bytesused; - mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused; + maxlen = buf->length - buf->bytesused; + mem = buf->mem + buf->bytesused; nbytes = min((unsigned int)len, maxlen); memcpy(mem, data, nbytes); - buf->buf.bytesused += nbytes; + buf->bytesused += nbytes; /* Complete the current frame if the buffer size was exceeded. */ if (len > maxlen) { @@ -530,7 +1066,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { /* Mark the buffer as done if the EOF marker is set. */ - if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) { + if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n"); if (data[0] == len) uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n"); @@ -568,8 +1104,8 @@ static int uvc_video_encode_data(struct uvc_streaming *stream, void *mem; /* Copy video data to the URB buffer. */ - mem = queue->mem + buf->buf.m.offset + queue->buf_used; - nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); + mem = buf->mem + queue->buf_used; + nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used); nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size, nbytes); memcpy(data, mem, nbytes); @@ -624,7 +1160,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, urb->iso_frame_desc[i].actual_length); if (buf->state == UVC_BUF_STATE_READY) { - if (buf->buf.length != buf->buf.bytesused && + if (buf->length != buf->bytesused && !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)) buf->error = 1; @@ -724,12 +1260,12 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, stream->bulk.payload_size += ret; len -= ret; - if (buf->buf.bytesused == stream->queue.buf_used || + if (buf->bytesused == stream->queue.buf_used || stream->bulk.payload_size == stream->bulk.max_payload_size) { - if (buf->buf.bytesused == stream->queue.buf_used) { + if (buf->bytesused == stream->queue.buf_used) { stream->queue.buf_used = 0; buf->state = UVC_BUF_STATE_READY; - buf->buf.sequence = ++stream->sequence; + buf->buf.v4l2_buf.sequence = ++stream->sequence; uvc_queue_next_buffer(&stream->queue, buf); stream->last_fid ^= UVC_STREAM_FID; } @@ -870,6 +1406,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) struct urb *urb; unsigned int i; + uvc_video_stats_stop(stream); + for (i = 0; i < UVC_URBS; ++i) { urb = stream->urb[i]; if (urb == NULL) @@ -882,6 +1420,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) if (free_buffers) uvc_free_urb_buffers(stream); + + uvc_video_clock_cleanup(stream); } /* @@ -1009,6 +1549,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) stream->bulk.skip_payload = 0; stream->bulk.payload_size = 0; + uvc_video_stats_start(stream); + + ret = uvc_video_clock_init(stream); + if (ret < 0) + return ret; + if (intf->num_altsetting > 1) { struct usb_host_endpoint *best_ep = NULL; unsigned int best_psize = 3 * 1024; @@ -1283,6 +1829,11 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) return ret; } - return uvc_init_video(stream, GFP_KERNEL); -} + ret = uvc_init_video(stream, GFP_KERNEL); + if (ret < 0) { + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + uvc_queue_enable(&stream->queue, 0); + } + return ret; +} diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 4c1392ebcd4b..67f88d85bb16 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -13,6 +13,7 @@ #include <linux/videodev2.h> #include <media/media-device.h> #include <media/v4l2-device.h> +#include <media/videobuf2-core.h> /* -------------------------------------------------------------------------- * UVC constants @@ -113,6 +114,7 @@ /* Maximum allowed number of control mappings per device */ #define UVC_MAX_CONTROL_MAPPINGS 1024 +#define UVC_MAX_CONTROL_MENU_ENTRIES 32 /* Devices quirks */ #define UVC_QUIRK_STATUS_INTERVAL 0x00000001 @@ -319,35 +321,30 @@ enum uvc_buffer_state { }; struct uvc_buffer { - unsigned long vma_use_count; - struct list_head stream; - - /* Touched by interrupt handler. */ - struct v4l2_buffer buf; + struct vb2_buffer buf; struct list_head queue; - wait_queue_head_t wait; + enum uvc_buffer_state state; unsigned int error; + + void *mem; + unsigned int length; + unsigned int bytesused; + + u32 pts; }; -#define UVC_QUEUE_STREAMING (1 << 0) -#define UVC_QUEUE_DISCONNECTED (1 << 1) -#define UVC_QUEUE_DROP_CORRUPTED (1 << 2) +#define UVC_QUEUE_DISCONNECTED (1 << 0) +#define UVC_QUEUE_DROP_CORRUPTED (1 << 1) struct uvc_video_queue { - enum v4l2_buf_type type; + struct vb2_queue queue; + struct mutex mutex; /* Protects queue */ - void *mem; unsigned int flags; - - unsigned int count; - unsigned int buf_size; unsigned int buf_used; - struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; - struct mutex mutex; /* protects buffers and mainqueue */ - spinlock_t irqlock; /* protects irqqueue */ - struct list_head mainqueue; + spinlock_t irqlock; /* Protects irqqueue */ struct list_head irqqueue; }; @@ -362,6 +359,51 @@ struct uvc_video_chain { struct mutex ctrl_mutex; /* Protects ctrl.info */ }; +struct uvc_stats_frame { + unsigned int size; /* Number of bytes captured */ + unsigned int first_data; /* Index of the first non-empty packet */ + + unsigned int nb_packets; /* Number of packets */ + unsigned int nb_empty; /* Number of empty packets */ + unsigned int nb_invalid; /* Number of packets with an invalid header */ + unsigned int nb_errors; /* Number of packets with the error bit set */ + + unsigned int nb_pts; /* Number of packets with a PTS timestamp */ + unsigned int nb_pts_diffs; /* Number of PTS differences inside a frame */ + unsigned int last_pts_diff; /* Index of the last PTS difference */ + bool has_initial_pts; /* Whether the first non-empty packet has a PTS */ + bool has_early_pts; /* Whether a PTS is present before the first non-empty packet */ + u32 pts; /* PTS of the last packet */ + + unsigned int nb_scr; /* Number of packets with a SCR timestamp */ + unsigned int nb_scr_diffs; /* Number of SCR.STC differences inside a frame */ + u16 scr_sof; /* SCR.SOF of the last packet */ + u32 scr_stc; /* SCR.STC of the last packet */ +}; + +struct uvc_stats_stream { + struct timespec start_ts; /* Stream start timestamp */ + struct timespec stop_ts; /* Stream stop timestamp */ + + unsigned int nb_frames; /* Number of frames */ + + unsigned int nb_packets; /* Number of packets */ + unsigned int nb_empty; /* Number of empty packets */ + unsigned int nb_invalid; /* Number of packets with an invalid header */ + unsigned int nb_errors; /* Number of packets with the error bit set */ + + unsigned int nb_pts_constant; /* Number of frames with constant PTS */ + unsigned int nb_pts_early; /* Number of frames with early PTS */ + unsigned int nb_pts_initial; /* Number of frames with initial PTS */ + + unsigned int nb_scr_count_ok; /* Number of frames with at least one SCR per non empty packet */ + unsigned int nb_scr_diffs_ok; /* Number of frames with varying SCR.STC */ + unsigned int scr_sof_count; /* STC.SOF counter accumulated since stream start */ + unsigned int scr_sof; /* STC.SOF of the last packet */ + unsigned int min_sof; /* Minimum STC.SOF value */ + unsigned int max_sof; /* Maximum STC.SOF value */ +}; + struct uvc_streaming { struct list_head list; struct uvc_device *dev; @@ -387,6 +429,7 @@ struct uvc_streaming { */ struct mutex mutex; + /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; void (*decode) (struct urb *urb, struct uvc_streaming *video, @@ -408,6 +451,32 @@ struct uvc_streaming { __u32 sequence; __u8 last_fid; + + /* debugfs */ + struct dentry *debugfs_dir; + struct { + struct uvc_stats_frame frame; + struct uvc_stats_stream stream; + } stats; + + /* Timestamps support. */ + struct uvc_clock { + struct uvc_clock_sample { + u32 dev_stc; + u16 dev_sof; + struct timespec host_ts; + u16 host_sof; + } *samples; + + unsigned int head; + unsigned int count; + unsigned int size; + + u16 last_sof; + u16 sof_offset; + + spinlock_t lock; + } clock; }; enum uvc_device_state { @@ -479,9 +548,12 @@ struct uvc_driver { #define UVC_TRACE_SUSPEND (1 << 8) #define UVC_TRACE_STATUS (1 << 9) #define UVC_TRACE_VIDEO (1 << 10) +#define UVC_TRACE_STATS (1 << 11) +#define UVC_TRACE_CLOCK (1 << 12) #define UVC_WARN_MINMAX 0 #define UVC_WARN_PROBE_DEF 1 +#define UVC_WARN_XU_GET_RES 2 extern unsigned int uvc_clock_param; extern unsigned int uvc_no_drop_param; @@ -516,8 +588,8 @@ extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); extern void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted); extern int uvc_alloc_buffers(struct uvc_video_queue *queue, - unsigned int nbuffers, unsigned int buflength); -extern int uvc_free_buffers(struct uvc_video_queue *queue); + struct v4l2_requestbuffers *rb); +extern void uvc_free_buffers(struct uvc_video_queue *queue); extern int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); extern int uvc_queue_buffer(struct uvc_video_queue *queue, @@ -539,7 +611,7 @@ extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, extern int uvc_queue_allocated(struct uvc_video_queue *queue); static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { - return queue->flags & UVC_QUEUE_STREAMING; + return vb2_is_streaming(&queue->queue); } /* V4L2 interface */ @@ -556,10 +628,11 @@ extern int uvc_video_resume(struct uvc_streaming *stream, int reset); extern int uvc_video_enable(struct uvc_streaming *stream, int enable); extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -extern int uvc_commit_video(struct uvc_streaming *stream, - struct uvc_streaming_control *ctrl); extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, __u8 intfnum, __u8 cs, void *data, __u16 size); +void uvc_video_clock_update(struct uvc_streaming *stream, + struct v4l2_buffer *v4l2_buf, + struct uvc_buffer *buf); /* Status */ extern int uvc_status_init(struct uvc_device *dev); @@ -612,4 +685,13 @@ extern struct usb_host_endpoint *uvc_find_endpoint( void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, struct uvc_buffer *buf); +/* debugfs and statistics */ +int uvc_debugfs_init(void); +void uvc_debugfs_cleanup(void); +int uvc_debugfs_init_stream(struct uvc_streaming *stream); +void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream); + +size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, + size_t size); + #endif diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index c68531b88279..af4419e6c658 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -985,6 +985,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_CROPCAP: case VIDIOC_G_CROP: case VIDIOC_S_CROP: + case VIDIOC_G_SELECTION: + case VIDIOC_S_SELECTION: case VIDIOC_G_JPEGCOMP: case VIDIOC_S_JPEGCOMP: case VIDIOC_QUERYSTD: diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 0f415dade05a..da1f4c2d2d4b 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -467,6 +467,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2"; case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Minimum Number of Capture Buffers"; case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Minimum Number of Output Buffers"; + case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; /* MPEG controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -1108,8 +1109,8 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, INIT_LIST_HEAD(&hdl->ctrls); INIT_LIST_HEAD(&hdl->ctrl_refs); hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; - hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets, - GFP_KERNEL); + hdl->buckets = kcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]), + GFP_KERNEL); hdl->error = hdl->buckets ? 0 : -ENOMEM; return hdl->error; } diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index a5c9ed128b97..96e9615663e9 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -146,10 +146,9 @@ static void v4l2_device_release(struct device *cd) struct v4l2_device *v4l2_dev = vdev->v4l2_dev; mutex_lock(&videodev_lock); - if (video_device[vdev->minor] != vdev) { - mutex_unlock(&videodev_lock); + if (WARN_ON(video_device[vdev->minor] != vdev)) { /* should not happen */ - WARN_ON(1); + mutex_unlock(&videodev_lock); return; } @@ -168,7 +167,7 @@ static void v4l2_device_release(struct device *cd) mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + if (v4l2_dev && v4l2_dev->mdev && vdev->vfl_type != VFL_TYPE_SUBDEV) media_device_unregister_entity(&vdev->entity); #endif @@ -556,8 +555,7 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->minor = -1; /* the release callback MUST be present */ - WARN_ON(!vdev->release); - if (!vdev->release) + if (WARN_ON(!vdev->release)) return -EINVAL; /* v4l2_fh support */ @@ -703,8 +701,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; - vdev->entity.v4l.major = VIDEO_MAJOR; - vdev->entity.v4l.minor = vdev->minor; + vdev->entity.info.v4l.major = VIDEO_MAJOR; + vdev->entity.info.v4l.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 0edd618b9ddf..1f203b85a637 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -234,8 +234,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) goto clean_up; } #if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.v4l.major = VIDEO_MAJOR; - sd->entity.v4l.minor = vdev->minor; + sd->entity.info.v4l.major = VIDEO_MAJOR; + sd->entity.info.v4l.minor = vdev->minor; #endif sd->devnode = vdev; } diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index e1da8fc9dd2f..77feeb67e2db 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -238,6 +238,8 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", + [_IOC_NR(VIDIOC_G_SELECTION)] = "VIDIOC_G_SELECTION", + [_IOC_NR(VIDIOC_S_SELECTION)] = "VIDIOC_S_SELECTION", [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", @@ -1547,11 +1549,32 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_crop *p = arg; - if (!ops->vidioc_g_crop) + if (!ops->vidioc_g_crop && !ops->vidioc_g_selection) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_g_crop(file, fh, p); + + if (ops->vidioc_g_crop) { + ret = ops->vidioc_g_crop(file, fh, p); + } else { + /* simulate capture crop using selection api */ + struct v4l2_selection s = { + .type = p->type, + }; + + /* crop means compose for output devices */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else + s.target = V4L2_SEL_TGT_CROP_ACTIVE; + + ret = ops->vidioc_g_selection(file, fh, &s); + + /* copying results to old structure on success */ + if (!ret) + p->c = s.r; + } + if (!ret) dbgrect(vfd, "", &p->c); break; @@ -1560,15 +1583,65 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_crop *p = arg; - if (!ops->vidioc_s_crop) + if (!ops->vidioc_s_crop && !ops->vidioc_s_selection) break; + if (ret_prio) { ret = ret_prio; break; } dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); - ret = ops->vidioc_s_crop(file, fh, p); + + if (ops->vidioc_s_crop) { + ret = ops->vidioc_s_crop(file, fh, p); + } else { + /* simulate capture crop using selection api */ + struct v4l2_selection s = { + .type = p->type, + .r = p->c, + }; + + /* crop means compose for output devices */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else + s.target = V4L2_SEL_TGT_CROP_ACTIVE; + + ret = ops->vidioc_s_selection(file, fh, &s); + } + break; + } + case VIDIOC_G_SELECTION: + { + struct v4l2_selection *p = arg; + + if (!ops->vidioc_g_selection) + break; + + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + + ret = ops->vidioc_g_selection(file, fh, p); + if (!ret) + dbgrect(vfd, "", &p->r); + break; + } + case VIDIOC_S_SELECTION: + { + struct v4l2_selection *p = arg; + + if (!ops->vidioc_s_selection) + break; + + if (ret_prio) { + ret = ret_prio; + break; + } + + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); + dbgrect(vfd, "", &p->r); + + ret = ops->vidioc_s_selection(file, fh, p); break; } case VIDIOC_CROPCAP: @@ -1576,11 +1649,42 @@ static long __video_do_ioctl(struct file *file, struct v4l2_cropcap *p = arg; /*FIXME: Should also show v4l2_fract pixelaspect */ - if (!ops->vidioc_cropcap) + if (!ops->vidioc_cropcap && !ops->vidioc_g_selection) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = ops->vidioc_cropcap(file, fh, p); + if (ops->vidioc_cropcap) { + ret = ops->vidioc_cropcap(file, fh, p); + } else { + struct v4l2_selection s = { .type = p->type }; + + /* obtaining bounds */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_BOUNDS; + else + s.target = V4L2_SEL_TGT_CROP_BOUNDS; + + ret = ops->vidioc_g_selection(file, fh, &s); + if (ret) + break; + p->bounds = s.r; + + /* obtaining defrect */ + if (V4L2_TYPE_IS_OUTPUT(p->type)) + s.target = V4L2_SEL_TGT_COMPOSE_DEFAULT; + else + s.target = V4L2_SEL_TGT_CROP_DEFAULT; + + ret = ops->vidioc_g_selection(file, fh, &s); + if (ret) + break; + p->defrect = s.r; + + /* setting trivial pixelaspect */ + p->pixelaspect.numerator = 1; + p->pixelaspect.denominator = 1; + } + if (!ret) { dbgrect(vfd, "bounds ", &p->bounds); dbgrect(vfd, "defrect ", &p->defrect); @@ -2226,6 +2330,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, struct v4l2_ext_controls *ctrls = parg; if (ctrls->count != 0) { + if (ctrls->count > V4L2_CID_MAX_CTRLS) { + ret = -EINVAL; + break; + } *user_ptr = (void __user *)ctrls->controls; *kernel_ptr = (void *)&ctrls->controls; *array_size = sizeof(struct v4l2_ext_control) diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 65ade5f03c2e..41d118ee2de6 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -193,6 +193,10 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return v4l2_subdev_call(sd, core, s_register, p); } #endif + + case VIDIOC_LOG_STATUS: + return v4l2_subdev_call(sd, core, log_status); + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index cbf13d09b4ac..20f7237b8242 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -34,13 +34,13 @@ MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver"); MODULE_LICENSE("GPL"); -static int flip_image; +static bool flip_image; module_param(flip_image, bool, 0444); MODULE_PARM_DESC(flip_image, "If set, the sensor will be instructed to flip the image " "vertically."); -static int override_serial; +static bool override_serial; module_param(override_serial, bool, 0444); MODULE_PARM_DESC(override_serial, "The camera driver will normally refuse to load if " @@ -156,14 +156,10 @@ static struct via_format { .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, .bpp = 2, }, - { - .desc = "RGB 565", - .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE, - .bpp = 2, - }, /* RGB444 and Bayer should be doable, but have never been - tested with this driver. */ + tested with this driver. RGB565 seems to work at the default + resolution, but results in color corruption when being scaled by + viacam_set_scaled(), and is disabled as a result. */ }; #define N_VIA_FMTS ARRAY_SIZE(via_formats) @@ -1504,14 +1500,4 @@ static struct platform_driver viacam_driver = { .remove = viacam_remove, }; -static int viacam_init(void) -{ - return platform_driver_register(&viacam_driver); -} -module_init(viacam_init); - -static void viacam_exit(void) -{ - platform_driver_unregister(&viacam_driver); -} -module_exit(viacam_exit); +module_platform_driver(viacam_driver); diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 3de7c7e4402d..59cb54aa2946 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -226,9 +226,10 @@ static int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, } /* register network adapter */ - dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); - if (dvb->net.dvbdev == NULL) { - result = -ENOMEM; + result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); + if (result < 0) { + printk(KERN_WARNING "%s: dvb_net_init failed (errno = %d)\n", + dvb->name, result); goto fail_fe_conn; } return 0; diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 95a3f5e82aef..2e8f1df775b6 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -30,7 +30,7 @@ module_param(debug, int, 0644); printk(KERN_DEBUG "vb2: " fmt, ## arg); \ } while (0) -#define call_memop(q, plane, op, args...) \ +#define call_memop(q, op, args...) \ (((q)->mem_ops->op) ? \ ((q)->mem_ops->op(args)) : 0) @@ -52,7 +52,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) /* Allocate memory for all planes in this buffer */ for (plane = 0; plane < vb->num_planes; ++plane) { - mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], + mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], q->plane_sizes[plane]); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -65,8 +65,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) return 0; free: /* Free already allocated memory if one of the allocations failed */ - for (; plane > 0; --plane) - call_memop(q, plane, put, vb->planes[plane - 1].mem_priv); + for (; plane > 0; --plane) { + call_memop(q, put, vb->planes[plane - 1].mem_priv); + vb->planes[plane - 1].mem_priv = NULL; + } return -ENOMEM; } @@ -80,10 +82,10 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb) unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { - call_memop(q, plane, put, vb->planes[plane].mem_priv); + call_memop(q, put, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; - dprintk(3, "Freed plane %d of buffer %d\n", - plane, vb->v4l2_buf.index); + dprintk(3, "Freed plane %d of buffer %d\n", plane, + vb->v4l2_buf.index); } } @@ -97,12 +99,9 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { - void *mem_priv = vb->planes[plane].mem_priv; - - if (mem_priv) { - call_memop(q, plane, put_userptr, mem_priv); - vb->planes[plane].mem_priv = NULL; - } + if (vb->planes[plane].mem_priv) + call_memop(q, put_userptr, vb->planes[plane].mem_priv); + vb->planes[plane].mem_priv = NULL; } } @@ -305,7 +304,7 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) * case anyway. If num_users() returns more than 1, * we are not the only user of the plane's memory. */ - if (mem_priv && call_memop(q, plane, num_users, mem_priv) > 1) + if (mem_priv && call_memop(q, num_users, mem_priv) > 1) return true; } return false; @@ -731,10 +730,10 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) { struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes) + if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv); + return call_memop(q, vaddr, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_vaddr); @@ -754,10 +753,10 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) { struct vb2_queue *q = vb->vb2_queue; - if (plane_no > vb->num_planes) + if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv) return NULL; - return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv); + return call_memop(q, cookie, vb->planes[plane_no].mem_priv); } EXPORT_SYMBOL_GPL(vb2_plane_cookie); @@ -883,7 +882,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) for (plane = 0; plane < vb->num_planes; ++plane) { /* Skip the plane if already verified */ - if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr + if (vb->v4l2_planes[plane].m.userptr && + vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr && vb->v4l2_planes[plane].length == planes[plane].length) continue; @@ -898,27 +898,23 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) /* Release previously acquired memory if present */ if (vb->planes[plane].mem_priv) - call_memop(q, plane, put_userptr, - vb->planes[plane].mem_priv); + call_memop(q, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; /* Acquire each plane's memory */ - if (q->mem_ops->get_userptr) { - mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane], - planes[plane].m.userptr, - planes[plane].length, - write); - if (IS_ERR(mem_priv)) { - dprintk(1, "qbuf: failed acquiring userspace " + mem_priv = call_memop(q, get_userptr, q->alloc_ctx[plane], + planes[plane].m.userptr, + planes[plane].length, write); + if (IS_ERR_OR_NULL(mem_priv)) { + dprintk(1, "qbuf: failed acquiring userspace " "memory for plane %d\n", plane); - ret = PTR_ERR(mem_priv); - goto err; - } - vb->planes[plane].mem_priv = mem_priv; + ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL; + goto err; } + vb->planes[plane].mem_priv = mem_priv; } /* @@ -943,8 +939,7 @@ err: /* In case of errors, release planes that were already acquired */ for (plane = 0; plane < vb->num_planes; ++plane) { if (vb->planes[plane].mem_priv) - call_memop(q, plane, put_userptr, - vb->planes[plane].mem_priv); + call_memop(q, put_userptr, vb->planes[plane].mem_priv); vb->planes[plane].mem_priv = NULL; vb->v4l2_planes[plane].m.userptr = 0; vb->v4l2_planes[plane].length = 0; @@ -1081,46 +1076,76 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf); */ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) { + struct rw_semaphore *mmap_sem = NULL; struct vb2_buffer *vb; - int ret; + int ret = 0; + + /* + * In case of user pointer buffers vb2 allocator needs to get direct + * access to userspace pages. This requires getting read access on + * mmap semaphore in the current process structure. The same + * semaphore is taken before calling mmap operation, while both mmap + * and qbuf are called by the driver or v4l2 core with driver's lock + * held. To avoid a AB-BA deadlock (mmap_sem then driver's lock in + * mmap and driver's lock then mmap_sem in qbuf) the videobuf2 core + * release driver's lock, takes mmap_sem and then takes again driver's + * lock. + * + * To avoid race with other vb2 calls, which might be called after + * releasing driver's lock, this operation is performed at the + * beggining of qbuf processing. This way the queue status is + * consistent after getting driver's lock back. + */ + if (q->memory == V4L2_MEMORY_USERPTR) { + mmap_sem = ¤t->mm->mmap_sem; + call_qop(q, wait_prepare, q); + down_read(mmap_sem); + call_qop(q, wait_finish, q); + } if (q->fileio) { dprintk(1, "qbuf: file io in progress\n"); - return -EBUSY; + ret = -EBUSY; + goto unlock; } if (b->type != q->type) { dprintk(1, "qbuf: invalid buffer type\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (b->index >= q->num_buffers) { dprintk(1, "qbuf: buffer index out of range\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } vb = q->bufs[b->index]; if (NULL == vb) { /* Should never happen */ dprintk(1, "qbuf: buffer is NULL\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (b->memory != q->memory) { dprintk(1, "qbuf: invalid memory type\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: ret = __buf_prepare(vb, b); if (ret) - return ret; + goto unlock; case VB2_BUF_STATE_PREPARED: break; default: dprintk(1, "qbuf: buffer already in use\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } /* @@ -1141,7 +1166,10 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) __fill_v4l2_buffer(vb, b); dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); - return 0; +unlock: + if (mmap_sem) + up_read(mmap_sem); + return ret; } EXPORT_SYMBOL_GPL(vb2_qbuf); @@ -1521,7 +1549,6 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) { unsigned long off = vma->vm_pgoff << PAGE_SHIFT; - struct vb2_plane *vb_plane; struct vb2_buffer *vb; unsigned int buffer, plane; int ret; @@ -1558,9 +1585,8 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) return ret; vb = q->bufs[buffer]; - vb_plane = &vb->planes[plane]; - ret = q->mem_ops->mmap(vb_plane->mem_priv, vma); + ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); if (ret) return ret; diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index 3bad8b105fea..25c3b360e1ad 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -140,7 +140,6 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, if (!buf->pages) goto userptr_fail_pages_array_alloc; - down_read(¤t->mm->mmap_sem); num_pages_from_user = get_user_pages(current, current->mm, vaddr & PAGE_MASK, buf->sg_desc.num_pages, @@ -148,7 +147,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, 1, /* force */ buf->pages, NULL); - up_read(¤t->mm->mmap_sem); + if (num_pages_from_user != buf->sg_desc.num_pages) goto userptr_fail_get_user_pages; diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c index 71a7a78c3fc0..c41cb60245d6 100644 --- a/drivers/media/video/videobuf2-memops.c +++ b/drivers/media/video/videobuf2-memops.c @@ -100,29 +100,26 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, unsigned long offset, start, end; unsigned long this_pfn, prev_pfn; dma_addr_t pa = 0; - int ret = -EFAULT; start = vaddr; offset = start & ~PAGE_MASK; end = start + size; - down_read(&mm->mmap_sem); vma = find_vma(mm, start); if (vma == NULL || vma->vm_end < end) - goto done; + return -EFAULT; for (prev_pfn = 0; start < end; start += PAGE_SIZE) { - ret = follow_pfn(vma, start, &this_pfn); + int ret = follow_pfn(vma, start, &this_pfn); if (ret) - goto done; + return ret; if (prev_pfn == 0) pa = this_pfn << PAGE_SHIFT; - else if (this_pfn != prev_pfn + 1) { - ret = -EFAULT; - goto done; - } + else if (this_pfn != prev_pfn + 1) + return -EFAULT; + prev_pfn = this_pfn; } @@ -130,16 +127,11 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, * Memory is contigous, lock vma and return to the caller */ *res_vma = vb2_get_vma(vma); - if (*res_vma == NULL) { - ret = -ENOMEM; - goto done; - } - *res_pa = pa + offset; - ret = 0; + if (*res_vma == NULL) + return -ENOMEM; -done: - up_read(&mm->mmap_sem); - return ret; + *res_pa = pa + offset; + return 0; } EXPORT_SYMBOL_GPL(vb2_get_contig_userptr); diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c index a3a884234059..4e789a178f8a 100644 --- a/drivers/media/video/videobuf2-vmalloc.c +++ b/drivers/media/video/videobuf2-vmalloc.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/mm.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/vmalloc.h> @@ -20,7 +21,10 @@ struct vb2_vmalloc_buf { void *vaddr; + struct page **pages; + int write; unsigned long size; + unsigned int n_pages; atomic_t refcount; struct vb2_vmarea_handler handler; }; @@ -31,7 +35,7 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) { struct vb2_vmalloc_buf *buf; - buf = kzalloc(sizeof *buf, GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return NULL; @@ -42,15 +46,12 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) buf->handler.arg = buf; if (!buf->vaddr) { - printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size); + pr_debug("vmalloc of size %ld failed\n", buf->size); kfree(buf); return NULL; } atomic_inc(&buf->refcount); - printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n", - buf->size, buf->vaddr); - return buf; } @@ -59,21 +60,84 @@ static void vb2_vmalloc_put(void *buf_priv) struct vb2_vmalloc_buf *buf = buf_priv; if (atomic_dec_and_test(&buf->refcount)) { - printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n", - __func__, buf->vaddr); vfree(buf->vaddr); kfree(buf); } } -static void *vb2_vmalloc_vaddr(void *buf_priv) +static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_vmalloc_buf *buf; + unsigned long first, last; + int n_pages, offset; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return NULL; + + buf->write = write; + offset = vaddr & ~PAGE_MASK; + buf->size = size; + + first = vaddr >> PAGE_SHIFT; + last = (vaddr + size - 1) >> PAGE_SHIFT; + buf->n_pages = last - first + 1; + buf->pages = kzalloc(buf->n_pages * sizeof(struct page *), GFP_KERNEL); + if (!buf->pages) + goto fail_pages_array_alloc; + + /* current->mm->mmap_sem is taken by videobuf2 core */ + n_pages = get_user_pages(current, current->mm, vaddr & PAGE_MASK, + buf->n_pages, write, 1, /* force */ + buf->pages, NULL); + if (n_pages != buf->n_pages) + goto fail_get_user_pages; + + buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, PAGE_KERNEL); + if (!buf->vaddr) + goto fail_get_user_pages; + + buf->vaddr += offset; + return buf; + +fail_get_user_pages: + pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages, + buf->n_pages); + while (--n_pages >= 0) + put_page(buf->pages[n_pages]); + kfree(buf->pages); + +fail_pages_array_alloc: + kfree(buf); + + return NULL; +} + +static void vb2_vmalloc_put_userptr(void *buf_priv) { struct vb2_vmalloc_buf *buf = buf_priv; + unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; + unsigned int i; + + if (vaddr) + vm_unmap_ram((void *)vaddr, buf->n_pages); + for (i = 0; i < buf->n_pages; ++i) { + if (buf->write) + set_page_dirty_lock(buf->pages[i]); + put_page(buf->pages[i]); + } + kfree(buf->pages); + kfree(buf); +} - BUG_ON(!buf); +static void *vb2_vmalloc_vaddr(void *buf_priv) +{ + struct vb2_vmalloc_buf *buf = buf_priv; if (!buf->vaddr) { - printk(KERN_ERR "Address of an unallocated plane requested\n"); + pr_err("Address of an unallocated plane requested " + "or cannot map user pointer\n"); return NULL; } @@ -92,13 +156,13 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) int ret; if (!buf) { - printk(KERN_ERR "No memory to map\n"); + pr_err("No memory to map\n"); return -EINVAL; } ret = remap_vmalloc_range(vma, buf->vaddr, 0); if (ret) { - printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret); + pr_err("Remapping vmalloc memory, error: %d\n", ret); return ret; } @@ -121,6 +185,8 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) const struct vb2_mem_ops vb2_vmalloc_memops = { .alloc = vb2_vmalloc_alloc, .put = vb2_vmalloc_put, + .get_userptr = vb2_vmalloc_get_userptr, + .put_userptr = vb2_vmalloc_put_userptr, .vaddr = vb2_vmalloc_vaddr, .mmap = vb2_vmalloc_mmap, .num_users = vb2_vmalloc_num_users, diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 52a0a3736c82..4d7391ec8001 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -708,7 +708,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb, size, count); /* allocate memory for table with virtual (page) addresses */ - fb->desc_table.virtual = (unsigned long *) + fb->desc_table.virtual = kmalloc(count * sizeof(unsigned long), GFP_KERNEL); if (!fb->desc_table.virtual) return -ENOMEM; diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c index e8a27844bf39..e86173bd1327 100644 --- a/drivers/media/video/zoran/zoran_device.c +++ b/drivers/media/video/zoran/zoran_device.c @@ -57,7 +57,7 @@ ZR36057_ISR_GIRQ1 | \ ZR36057_ISR_JPEGRepIRQ ) -static int lml33dpath; /* default = 0 +static bool lml33dpath; /* default = 0 * 1 will use digital path in capture * mode instead of analog. It can be * used for picture adjustments using diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/video/zoran/zr36060.c index 5e4f57cbf314..f08546fe2234 100644 --- a/drivers/media/video/zoran/zr36060.c +++ b/drivers/media/video/zoran/zr36060.c @@ -50,7 +50,7 @@ /* amount of chips attached via this driver */ static int zr36060_codecs; -static int low_bitrate; +static bool low_bitrate; module_param(low_bitrate, bool, 0); MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 6ce70e9615d3..5319e9b65847 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -21,7 +21,7 @@ #define DRIVER_NAME "jmb38x_ms" -static int no_dma; +static bool no_dma; module_param(no_dma, bool, 0644); enum { diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 668f5c6a0399..29b2172ae18f 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -23,7 +23,7 @@ #include <linux/swab.h> #include "r592.h" -static int r592_enable_dma = 1; +static bool r592_enable_dma = 1; static int debug; static const char *tpc_names[] = { diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index b7aacf47703a..6902b83eb1b4 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -22,7 +22,7 @@ #define DRIVER_NAME "tifm_ms" -static int no_dma; +static bool no_dma; module_param(no_dma, bool, 0644); /* diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index e017dc88622a..f93dd9571c3c 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -12,51 +12,20 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/err.h> +#include <linux/regmap.h> #include <linux/mfd/88pm860x.h> #include <linux/slab.h> -static inline int pm860x_read_device(struct i2c_client *i2c, - int reg, int bytes, void *dest) -{ - unsigned char data; - int ret; - - data = (unsigned char)reg; - ret = i2c_master_send(i2c, &data, 1); - if (ret < 0) - return ret; - - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - return 0; -} - -static inline int pm860x_write_device(struct i2c_client *i2c, - int reg, int bytes, void *src) -{ - unsigned char buf[bytes + 1]; - int ret; - - buf[0] = (unsigned char)reg; - memcpy(&buf[1], src, bytes); - - ret = i2c_master_send(i2c, buf, bytes + 1); - if (ret < 0) - return ret; - return 0; -} - int pm860x_reg_read(struct i2c_client *i2c, int reg) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); - unsigned char data; + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; + unsigned int data; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_read_device(i2c, reg, 1, &data); - mutex_unlock(&chip->io_lock); - + ret = regmap_read(map, reg, &data); if (ret < 0) return ret; else @@ -68,12 +37,11 @@ int pm860x_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_write_device(i2c, reg, 1, &data); - mutex_unlock(&chip->io_lock); - + ret = regmap_write(map, reg, data); return ret; } EXPORT_SYMBOL(pm860x_reg_write); @@ -82,12 +50,11 @@ int pm860x_bulk_read(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_read_device(i2c, reg, count, buf); - mutex_unlock(&chip->io_lock); - + ret = regmap_raw_read(map, reg, buf, count); return ret; } EXPORT_SYMBOL(pm860x_bulk_read); @@ -96,12 +63,11 @@ int pm860x_bulk_write(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_write_device(i2c, reg, count, buf); - mutex_unlock(&chip->io_lock); - + ret = regmap_raw_write(map, reg, buf, count); return ret; } EXPORT_SYMBOL(pm860x_bulk_write); @@ -110,39 +76,78 @@ int pm860x_set_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); - unsigned char value; + struct regmap *map = (i2c == chip->client) ? chip->regmap + : chip->regmap_companion; int ret; - mutex_lock(&chip->io_lock); - ret = pm860x_read_device(i2c, reg, 1, &value); - if (ret < 0) - goto out; - value &= ~mask; - value |= data; - ret = pm860x_write_device(i2c, reg, 1, &value); -out: - mutex_unlock(&chip->io_lock); + ret = regmap_update_bits(map, reg, mask, data); return ret; } EXPORT_SYMBOL(pm860x_set_bits); +static int read_device(struct i2c_client *i2c, int reg, + int bytes, void *dest) +{ + unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; + unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; + struct i2c_adapter *adap = i2c->adapter; + struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0}, + {i2c->addr, I2C_M_RD, 0, msgbuf1}, + }; + int num = 1, ret = 0; + + if (dest == NULL) + return -EINVAL; + msgbuf0[0] = (unsigned char)reg; /* command */ + msg[1].len = bytes; + + /* if data needs to read back, num should be 2 */ + if (bytes > 0) + num = 2; + ret = adap->algo->master_xfer(adap, msg, num); + memcpy(dest, msgbuf1, bytes); + if (ret < 0) + return ret; + return 0; +} + +static int write_device(struct i2c_client *i2c, int reg, + int bytes, void *src) +{ + unsigned char buf[bytes + 1]; + struct i2c_adapter *adap = i2c->adapter; + struct i2c_msg msg; + int ret; + + buf[0] = (unsigned char)reg; + memcpy(&buf[1], src, bytes); + msg.addr = i2c->addr; + msg.flags = 0; + msg.len = bytes + 1; + msg.buf = buf; + + ret = adap->algo->master_xfer(adap, &msg, 1); + if (ret < 0) + return ret; + return 0; +} + int pm860x_page_reg_read(struct i2c_client *i2c, int reg) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero = 0; unsigned char data; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_read_device(i2c, reg, 1, &data); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = read_device(i2c, reg, 1, &data); if (ret >= 0) ret = (int)data; - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_reg_read); @@ -150,18 +155,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read); int pm860x_page_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_write_device(i2c, reg, 1, &data); - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = write_device(i2c, reg, 1, &data); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_reg_write); @@ -169,18 +173,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write); int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero = 0; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_read_device(i2c, reg, count, buf); - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xfa, 0, &zero); + read_device(i2c, 0xfb, 0, &zero); + read_device(i2c, 0xff, 0, &zero); + ret = read_device(i2c, reg, count, buf); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_bulk_read); @@ -188,18 +191,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read); int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, int count, unsigned char *buf) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero = 0; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_write_device(i2c, reg, count, buf); - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = write_device(i2c, reg, count, buf); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_bulk_write); @@ -207,25 +210,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write); int pm860x_page_set_bits(struct i2c_client *i2c, int reg, unsigned char mask, unsigned char data) { - struct pm860x_chip *chip = i2c_get_clientdata(i2c); unsigned char zero; unsigned char value; int ret; - mutex_lock(&chip->io_lock); - pm860x_write_device(i2c, 0xFA, 0, &zero); - pm860x_write_device(i2c, 0xFB, 0, &zero); - pm860x_write_device(i2c, 0xFF, 0, &zero); - ret = pm860x_read_device(i2c, reg, 1, &value); + i2c_lock_adapter(i2c->adapter); + read_device(i2c, 0xFA, 0, &zero); + read_device(i2c, 0xFB, 0, &zero); + read_device(i2c, 0xFF, 0, &zero); + ret = read_device(i2c, reg, 1, &value); if (ret < 0) goto out; value &= ~mask; value |= data; - ret = pm860x_write_device(i2c, reg, 1, &value); + ret = write_device(i2c, reg, 1, &value); out: - pm860x_write_device(i2c, 0xFE, 0, &zero); - pm860x_write_device(i2c, 0xFC, 0, &zero); - mutex_unlock(&chip->io_lock); + read_device(i2c, 0xFE, 0, &zero); + read_device(i2c, 0xFC, 0, &zero); + i2c_unlock_adapter(i2c->adapter); return ret; } EXPORT_SYMBOL(pm860x_page_set_bits); @@ -257,11 +259,17 @@ static int verify_addr(struct i2c_client *i2c) return 0; } +static struct regmap_config pm860x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + static int __devinit pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pm860x_platform_data *pdata = client->dev.platform_data; struct pm860x_chip *chip; + int ret; if (!pdata) { pr_info("No platform data in %s!\n", __func__); @@ -273,10 +281,17 @@ static int __devinit pm860x_probe(struct i2c_client *client, return -ENOMEM; chip->id = verify_addr(client); + chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + kfree(chip); + return ret; + } chip->client = client; i2c_set_clientdata(client, chip); chip->dev = &client->dev; - mutex_init(&chip->io_lock); dev_set_drvdata(chip->dev, chip); /* @@ -290,6 +305,14 @@ static int __devinit pm860x_probe(struct i2c_client *client, chip->companion_addr = pdata->companion_addr; chip->companion = i2c_new_dummy(chip->client->adapter, chip->companion_addr); + chip->regmap_companion = regmap_init_i2c(chip->companion, + &pm860x_regmap_config); + if (IS_ERR(chip->regmap_companion)) { + ret = PTR_ERR(chip->regmap_companion); + dev_err(&chip->companion->dev, + "Failed to allocate register map: %d\n", ret); + return ret; + } i2c_set_clientdata(chip->companion, chip); } @@ -302,7 +325,11 @@ static int __devexit pm860x_remove(struct i2c_client *client) struct pm860x_chip *chip = i2c_get_clientdata(client); pm860x_device_exit(chip); - i2c_unregister_device(chip->companion); + if (chip->companion) { + regmap_exit(chip->regmap_companion); + i2c_unregister_device(chip->companion); + } + regmap_exit(chip->regmap); kfree(chip); return 0; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 053208d31fb9..cd13e9f2f5e6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -12,6 +12,7 @@ config MFD_CORE config MFD_88PM860X bool "Support Marvell 88PM8606/88PM8607" depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C select MFD_CORE help This supports for Marvell 88PM8606/88PM8607 Power Management IC. @@ -199,7 +200,7 @@ config MENELAUS config TWL4030_CORE bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" - depends on I2C=y && GENERIC_HARDIRQS + depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN help Say yes here if you have TWL4030 / TWL6030 family chip on your board. This core driver provides register access and IRQ handling @@ -257,7 +258,7 @@ config TWL6040_CORE config MFD_STMPE bool "Support STMicroelectronics STMPE" - depends on I2C=y && GENERIC_HARDIRQS + depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS select MFD_CORE help Support for the STMPE family of I/O Expanders from @@ -278,6 +279,23 @@ config MFD_STMPE Keypad: stmpe-keypad Touchscreen: stmpe-ts +menu "STMPE Interface Drivers" +depends on MFD_STMPE + +config STMPE_I2C + bool "STMPE I2C Inteface" + depends on I2C=y + default y + help + This is used to enable I2C interface of STMPE + +config STMPE_SPI + bool "STMPE SPI Inteface" + depends on SPI_MASTER + help + This is used to enable SPI interface of STMPE +endmenu + config MFD_TC3589X bool "Support Toshiba TC35892 and variants" depends on I2C=y && GENERIC_HARDIRQS @@ -311,7 +329,7 @@ config MFD_TC6387XB config MFD_TC6393XB bool "Support Toshiba TC6393XB" - depends on GPIOLIB && ARM + depends on GPIOLIB && ARM && HAVE_CLK select MFD_CORE select MFD_TMIO help @@ -399,6 +417,17 @@ config MFD_MAX8998 additional drivers must be enabled in order to use the functionality of the device. +config MFD_S5M_CORE + bool "SAMSUNG S5M Series Support" + depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE + select REGMAP_I2C + help + Support for the Samsung Electronics S5M MFD series. + This driver provies common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device + config MFD_WM8400 tristate "Support Wolfson Microelectronics WM8400" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 47591fc7d0d2..b953bab934f7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o obj-$(CONFIG_MFD_STMPE) += stmpe.o +obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o +obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o @@ -109,3 +111,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o +obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 02c42015ba51..3aa36eb5c79b 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -407,13 +407,13 @@ static int aat2870_i2c_probe(struct i2c_client *client, aat2870->init(aat2870); if (aat2870->en_pin >= 0) { - ret = gpio_request(aat2870->en_pin, "aat2870-en"); + ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH, + "aat2870-en"); if (ret < 0) { dev_err(&client->dev, "Failed to request GPIO %d\n", aat2870->en_pin); goto out_kfree; } - gpio_direction_output(aat2870->en_pin, 1); } aat2870_enable(aat2870); @@ -468,9 +468,10 @@ static int aat2870_i2c_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM -static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int aat2870_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct aat2870_data *aat2870 = i2c_get_clientdata(client); aat2870_disable(aat2870); @@ -478,8 +479,9 @@ static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state) return 0; } -static int aat2870_i2c_resume(struct i2c_client *client) +static int aat2870_i2c_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct aat2870_data *aat2870 = i2c_get_clientdata(client); struct aat2870_register *reg = NULL; int i; @@ -495,12 +497,12 @@ static int aat2870_i2c_resume(struct i2c_client *client) return 0; } -#else -#define aat2870_i2c_suspend NULL -#define aat2870_i2c_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend, + aat2870_i2c_resume); -static struct i2c_device_id aat2870_i2c_id_table[] = { +static const struct i2c_device_id aat2870_i2c_id_table[] = { { "aat2870", 0 }, { } }; @@ -510,11 +512,10 @@ static struct i2c_driver aat2870_i2c_driver = { .driver = { .name = "aat2870", .owner = THIS_MODULE, + .pm = &aat2870_pm_ops, }, .probe = aat2870_i2c_probe, .remove = aat2870_i2c_remove, - .suspend = aat2870_i2c_suspend, - .resume = aat2870_i2c_resume, .id_table = aat2870_i2c_id_table, }; diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c index ec10629a0b0b..bd56a764dea1 100644 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -22,8 +22,8 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/random.h> -#include <linux/mfd/ab5500/ab5500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab5500.h> #include <linux/list.h> #include <linux/bitops.h> #include <linux/spinlock.h> diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c index b7b2d3483fd4..72006940937a 100644 --- a/drivers/mfd/ab5500-debugfs.c +++ b/drivers/mfd/ab5500-debugfs.c @@ -7,8 +7,8 @@ #include <linux/module.h> #include <linux/debugfs.h> #include <linux/seq_file.h> -#include <linux/mfd/ab5500/ab5500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab5500.h> #include <linux/uaccess.h> #include "ab5500-core.h" diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index d3d572b2317b..53e2a80f42fa 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -17,7 +17,7 @@ #include <linux/platform_device.h> #include <linux/mfd/core.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/regulator/ab8500.h> /* diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index dedb7f65cea6..9a0211aa8897 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -13,7 +13,7 @@ #include <linux/platform_device.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> static u32 debug_bank; static u32 debug_address; diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index e985d1701a83..c39fc716e1dc 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -18,9 +18,9 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/list.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500/gpadc.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/mfd/abx500/ab8500-gpadc.h> /* * GPADC register offsets diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c index 9be541c6b004..087fecd71ce0 100644 --- a/drivers/mfd/ab8500-i2c.c +++ b/drivers/mfd/ab8500-i2c.c @@ -10,7 +10,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/db8500-prcmu.h> static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data) diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index f20feefac190..c28d4eb1eff0 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -7,9 +7,9 @@ #include <linux/err.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500/sysctrl.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/mfd/abx500/ab8500-sysctrl.h> static struct device *sysctrl_dev; diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 155fa0407882..315fef5d466a 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -172,14 +172,14 @@ static void __devexit cs5535_mfd_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id cs5535_mfd_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(cs5535_mfd_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, { 0, } }; MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl); -static struct pci_driver cs5535_mfd_drv = { +static struct pci_driver cs5535_mfd_driver = { .name = DRV_NAME, .id_table = cs5535_mfd_pci_tbl, .probe = cs5535_mfd_probe, @@ -188,12 +188,12 @@ static struct pci_driver cs5535_mfd_drv = { static int __init cs5535_mfd_init(void) { - return pci_register_driver(&cs5535_mfd_drv); + return pci_register_driver(&cs5535_mfd_driver); } static void __exit cs5535_mfd_exit(void) { - pci_unregister_driver(&cs5535_mfd_drv); + pci_unregister_driver(&cs5535_mfd_driver); } module_init(cs5535_mfd_init); diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 8ad88da647b9..7710227d284e 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -308,8 +308,7 @@ static int add_children(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(config_inputs); i++) { int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset; - gpio_request(gpio, config_inputs[i].label); - gpio_direction_input(gpio); + gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label); /* make it easy for userspace to see these */ gpio_export(gpio, false); diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 97c27762174f..b76657eb0c51 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -485,17 +485,7 @@ static struct platform_driver intel_msic_driver = { }, }; -static int __init intel_msic_init(void) -{ - return platform_driver_register(&intel_msic_driver); -} -module_init(intel_msic_init); - -static void __exit intel_msic_exit(void) -{ - platform_driver_unregister(&intel_msic_driver); -} -module_exit(intel_msic_exit); +module_platform_driver(intel_msic_driver); MODULE_DESCRIPTION("Driver for Intel MSIC"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 5c2a06acb77f..a9223ed1b7c5 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -33,7 +33,7 @@ /* Module Parameters */ static unsigned int num_modules = CMODIO_MAX_MODULES; -static unsigned char *modules[CMODIO_MAX_MODULES] = { +static char *modules[CMODIO_MAX_MODULES] = { "empty", "empty", "empty", "empty", }; diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index ef39528088f2..87662a17dec6 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -181,7 +181,7 @@ static struct resource jz4740_battery_resources[] = { }, }; -const struct mfd_cell jz4740_adc_cells[] = { +static struct mfd_cell jz4740_adc_cells[] = { { .id = 0, .name = "jz4740-hwmon", @@ -338,17 +338,7 @@ static struct platform_driver jz4740_adc_driver = { }, }; -static int __init jz4740_adc_init(void) -{ - return platform_driver_register(&jz4740_adc_driver); -} -module_init(jz4740_adc_init); - -static void __exit jz4740_adc_exit(void) -{ - platform_driver_unregister(&jz4740_adc_driver); -} -module_exit(jz4740_adc_exit); +module_platform_driver(jz4740_adc_driver); MODULE_DESCRIPTION("JZ4740 SoC ADC driver"); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index ea1169b04779..abc421364a45 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -74,7 +74,7 @@ static struct mfd_cell tunnelcreek_cells[] = { }, }; -static struct pci_device_id lpc_sch_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, { 0, } diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 0219115e00c7..d9e4b36edee9 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -161,6 +161,8 @@ static int __devinit max8925_probe(struct i2c_client *client, chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR); i2c_set_clientdata(chip->adc, chip); + device_init_wakeup(&client->dev, 1); + max8925_device_init(chip, pdata); return 0; @@ -177,10 +179,35 @@ static int __devexit max8925_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int max8925_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct max8925_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + enable_irq_wake(chip->core_irq); + return 0; +} + +static int max8925_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct max8925_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + disable_irq_wake(chip->core_irq); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume); + static struct i2c_driver max8925_driver = { .driver = { .name = "max8925", .owner = THIS_MODULE, + .pm = &max8925_pm_ops, }, .probe = max8925_probe, .remove = __devexit_p(max8925_remove), diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 5be53ae9b61c..cb83a7ab53e7 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -43,7 +43,8 @@ static struct mfd_cell max8997_devs[] = { { .name = "max8997-battery", }, { .name = "max8997-haptic", }, { .name = "max8997-muic", }, - { .name = "max8997-flash", }, + { .name = "max8997-led", .id = 1 }, + { .name = "max8997-led", .id = 2 }, }; int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index de4096aee248..6ef56d28c056 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -176,6 +176,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, if (ret < 0) goto err; + device_init_wakeup(max8998->dev, max8998->wakeup); + return ret; err: @@ -210,7 +212,7 @@ static int max8998_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max8998_dev *max8998 = i2c_get_clientdata(i2c); - if (max8998->wakeup) + if (device_may_wakeup(dev)) irq_set_irq_wake(max8998->irq, 1); return 0; } @@ -220,7 +222,7 @@ static int max8998_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max8998_dev *max8998 = i2c_get_clientdata(i2c); - if (max8998->wakeup) + if (device_may_wakeup(dev)) irq_set_irq_wake(max8998->irq, 0); /* * In LP3974, if IRQ registers are not "read & clear" diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index e9619acc0237..7122386b4e3c 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -18,11 +18,15 @@ #include <linux/spi/spi.h> #include <linux/mfd/core.h> #include <linux/mfd/mc13xxx.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> struct mc13xxx { struct spi_device *spidev; struct mutex lock; int irq; + int flags; irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; void *irqdata[MC13XXX_NUM_IRQ]; @@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) int mc13xxx_get_flags(struct mc13xxx *mc13xxx) { - struct mc13xxx_platform_data *pdata = - dev_get_platdata(&mc13xxx->spidev->dev); - - return pdata->flags; + return mc13xxx->flags; } EXPORT_SYMBOL(mc13xxx_get_flags); @@ -615,13 +616,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, break; case MC13XXX_ADC_MODE_SINGLE_CHAN: - adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK; + adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK; adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT; adc1 |= MC13XXX_ADC1_RAND; break; case MC13XXX_ADC_MODE_MULT_CHAN: - adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK; + adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK; adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT; break; @@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); } +#ifdef CONFIG_OF +static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) +{ + struct device_node *np = mc13xxx->spidev->dev.of_node; + + if (!np) + return -ENODEV; + + if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL)) + mc13xxx->flags |= MC13XXX_USE_ADC; + + if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL)) + mc13xxx->flags |= MC13XXX_USE_CODEC; + + if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL)) + mc13xxx->flags |= MC13XXX_USE_RTC; + + if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL)) + mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN; + + return 0; +} +#else +static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx) +{ + return -ENODEV; +} +#endif + +static const struct spi_device_id mc13xxx_device_id[] = { + { + .name = "mc13783", + .driver_data = MC13XXX_ID_MC13783, + }, { + .name = "mc13892", + .driver_data = MC13XXX_ID_MC13892, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); + +static const struct of_device_id mc13xxx_dt_ids[] = { + { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, }, + { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids); + static int mc13xxx_probe(struct spi_device *spi) { + const struct of_device_id *of_id; + struct spi_driver *sdrv = to_spi_driver(spi->dev.driver); struct mc13xxx *mc13xxx; struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); enum mc13xxx_id id; int ret; - if (!pdata) { - dev_err(&spi->dev, "invalid platform data\n"); - return -EINVAL; - } + of_id = of_match_device(mc13xxx_dt_ids, &spi->dev); + if (of_id) + sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data]; mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); if (!mc13xxx) @@ -749,28 +800,33 @@ err_revision: mc13xxx_unlock(mc13xxx); - if (pdata->flags & MC13XXX_USE_ADC) + if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) + mc13xxx->flags = pdata->flags; + + if (mc13xxx->flags & MC13XXX_USE_ADC) mc13xxx_add_subdevice(mc13xxx, "%s-adc"); - if (pdata->flags & MC13XXX_USE_CODEC) + if (mc13xxx->flags & MC13XXX_USE_CODEC) mc13xxx_add_subdevice(mc13xxx, "%s-codec"); - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", - &pdata->regulators, sizeof(pdata->regulators)); - - if (pdata->flags & MC13XXX_USE_RTC) + if (mc13xxx->flags & MC13XXX_USE_RTC) mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); - if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) mc13xxx_add_subdevice(mc13xxx, "%s-ts"); - if (pdata->leds) + if (pdata) { + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", + &pdata->regulators, sizeof(pdata->regulators)); mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds, sizeof(*pdata->leds)); - - if (pdata->buttons) mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", pdata->buttons, sizeof(*pdata->buttons)); + } else { + mc13xxx_add_subdevice(mc13xxx, "%s-regulator"); + mc13xxx_add_subdevice(mc13xxx, "%s-led"); + mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton"); + } return 0; } @@ -788,25 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi) return 0; } -static const struct spi_device_id mc13xxx_device_id[] = { - { - .name = "mc13783", - .driver_data = MC13XXX_ID_MC13783, - }, { - .name = "mc13892", - .driver_data = MC13XXX_ID_MC13892, - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); - static struct spi_driver mc13xxx_driver = { .id_table = mc13xxx_device_id, .driver = { .name = "mc13xxx", - .bus = &spi_bus_type, .owner = THIS_MODULE, + .of_match_table = mc13xxx_dt_ids, }, .probe = mc13xxx_probe, .remove = __devexit_p(mc13xxx_remove), diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 84815f9ef636..63be60bc3455 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -26,9 +26,35 @@ #define to_mcp(d) container_of(d, struct mcp, attached_device) #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) +static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id, + const char *codec) +{ + while (id->name[0]) { + if (strcmp(codec, id->name) == 0) + return id; + id++; + } + return NULL; +} + +const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp) +{ + const struct mcp_driver *driver = + to_mcp_driver(mcp->attached_device.driver); + + return mcp_match_id(driver->id_table, mcp->codec); +} +EXPORT_SYMBOL(mcp_get_device_id); + static int mcp_bus_match(struct device *dev, struct device_driver *drv) { - return 1; + const struct mcp *mcp = to_mcp(dev); + const struct mcp_driver *driver = to_mcp_driver(drv); + + if (driver->id_table) + return !!mcp_match_id(driver->id_table, mcp->codec); + + return 0; } static int mcp_bus_probe(struct device *dev) @@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev) return ret; } +static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mcp *mcp = to_mcp(dev); + + add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec); + return 0; +} + static struct bus_type mcp_bus_type = { .name = "mcp", .match = mcp_bus_match, + .uevent = mcp_bus_uevent, .probe = mcp_bus_probe, .remove = mcp_bus_remove, .suspend = mcp_bus_suspend, @@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) } EXPORT_SYMBOL(mcp_host_alloc); -int mcp_host_register(struct mcp *mcp) +int mcp_host_register(struct mcp *mcp, void *pdata) { + if (!mcp->codec) + return -EINVAL; + + mcp->attached_device.platform_data = pdata; dev_set_name(&mcp->attached_device, "mcp0"); + request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec); return device_register(&mcp->attached_device); } EXPORT_SYMBOL(mcp_host_register); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 2dab02d9ac8b..9adc2eb69492 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -19,6 +19,7 @@ #include <linux/spinlock.h> #include <linux/platform_device.h> #include <linux/mfd/mcp.h> +#include <linux/io.h> #include <mach/dma.h> #include <mach/hardware.h> @@ -26,12 +27,19 @@ #include <asm/system.h> #include <mach/mcp.h> -#include <mach/assabet.h> - +/* Register offsets */ +#define MCCR0 0x00 +#define MCDR0 0x08 +#define MCDR1 0x0C +#define MCDR2 0x10 +#define MCSR 0x18 +#define MCCR1 0x00 struct mcp_sa11x0 { - u32 mccr0; - u32 mccr1; + u32 mccr0; + u32 mccr1; + unsigned char *mccr0_base; + unsigned char *mccr1_base; }; #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) @@ -39,25 +47,25 @@ struct mcp_sa11x0 { static void mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *priv = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x00007f00; - mccr0 |= divisor << 8; - Ser4MCCR0 = mccr0; + priv->mccr0 &= ~0x00007f00; + priv->mccr0 |= divisor << 8; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } static void mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) { - unsigned int mccr0; + struct mcp_sa11x0 *priv = priv(mcp); divisor /= 32; - mccr0 = Ser4MCCR0 & ~0x0000007f; - mccr0 |= divisor; - Ser4MCCR0 = mccr0; + priv->mccr0 &= ~0x0000007f; + priv->mccr0 |= divisor; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } /* @@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) { int ret = -ETIME; int i; + u32 mcpreg; + struct mcp_sa11x0 *priv = priv(mcp); - Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); + mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff); + __raw_writel(mcpreg, priv->mccr0_base + MCDR2); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CWC) { + mcpreg = __raw_readl(priv->mccr0_base + MCSR); + if (mcpreg & MCSR_CWC) { ret = 0; break; } @@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) { int ret = -ETIME; int i; + u32 mcpreg; + struct mcp_sa11x0 *priv = priv(mcp); - Ser4MCDR2 = reg << 17 | MCDR2_Rd; + mcpreg = reg << 17 | MCDR2_Rd; + __raw_writel(mcpreg, priv->mccr0_base + MCDR2); for (i = 0; i < 2; i++) { udelay(mcp->rw_timeout); - if (Ser4MCSR & MCSR_CRC) { - ret = Ser4MCDR2 & 0xffff; + mcpreg = __raw_readl(priv->mccr0_base + MCSR); + if (mcpreg & MCSR_CRC) { + ret = __raw_readl(priv->mccr0_base + MCDR2) + & 0xffff; break; } } @@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) static void mcp_sa11x0_enable(struct mcp *mcp) { - Ser4MCSR = -1; - Ser4MCCR0 |= MCCR0_MCE; + struct mcp_sa11x0 *priv = priv(mcp); + + __raw_writel(-1, priv->mccr0_base + MCSR); + priv->mccr0 |= MCCR0_MCE; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } static void mcp_sa11x0_disable(struct mcp *mcp) { - Ser4MCCR0 &= ~MCCR0_MCE; + struct mcp_sa11x0 *priv = priv(mcp); + + priv->mccr0 &= ~MCCR0_MCE; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); } /* @@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) struct mcp_plat_data *data = pdev->dev.platform_data; struct mcp *mcp; int ret; + struct mcp_sa11x0 *priv; + struct resource *res_mem0, *res_mem1; + u32 size0, size1; if (!data) return -ENODEV; - if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) + if (!data->codec) + return -ENODEV; + + res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem0) + return -ENODEV; + size0 = res_mem0->end - res_mem0->start + 1; + + res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res_mem1) + return -ENODEV; + size1 = res_mem1->end - res_mem1->start + 1; + + if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp")) return -EBUSY; + if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) { + ret = -EBUSY; + goto release; + } + mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); if (!mcp) { ret = -ENOMEM; - goto release; + goto release2; } + priv = priv(mcp); + mcp->owner = THIS_MODULE; mcp->ops = &mcp_sa11x0; mcp->sclk_rate = data->sclk_rate; - mcp->dma_audio_rd = DMA_Ser4MCP0Rd; - mcp->dma_audio_wr = DMA_Ser4MCP0Wr; - mcp->dma_telco_rd = DMA_Ser4MCP1Rd; - mcp->dma_telco_wr = DMA_Ser4MCP1Wr; - mcp->gpio_base = data->gpio_base; + mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0) + + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev; + mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0) + + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev; + mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1) + + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev; + mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1) + + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev; + mcp->codec = data->codec; platform_set_drvdata(pdev, mcp); - if (machine_is_assabet()) { - ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); - } - - /* - * Setup the PPC unit correctly. - */ - PPDR &= ~PPC_RXD4; - PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; - PSDR |= PPC_RXD4; - PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); - PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); - /* * Initialise device. Note that we initially * set the sampling rate to minimum. */ - Ser4MCSR = -1; - Ser4MCCR1 = data->mccr1; - Ser4MCCR0 = data->mccr0 | 0x7f7f; + priv->mccr0_base = ioremap(res_mem0->start, size0); + priv->mccr1_base = ioremap(res_mem1->start, size1); + + __raw_writel(-1, priv->mccr0_base + MCSR); + priv->mccr1 = data->mccr1; + priv->mccr0 = data->mccr0 | 0x7f7f; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); + __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1); /* * Calculate the read/write timeout (us) from the bit clock @@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / mcp->sclk_rate; - ret = mcp_host_register(mcp); + ret = mcp_host_register(mcp, data->codec_pdata); if (ret == 0) goto out; + release2: + release_mem_region(res_mem1->start, size1); release: - release_mem_region(0x80060000, 0x60); + release_mem_region(res_mem0->start, size0); platform_set_drvdata(pdev, NULL); out: return ret; } -static int mcp_sa11x0_remove(struct platform_device *dev) +static int mcp_sa11x0_remove(struct platform_device *pdev) { - struct mcp *mcp = platform_get_drvdata(dev); + struct mcp *mcp = platform_get_drvdata(pdev); + struct mcp_sa11x0 *priv = priv(mcp); + struct resource *res_mem; + u32 size; - platform_set_drvdata(dev, NULL); + platform_set_drvdata(pdev, NULL); mcp_host_unregister(mcp); - release_mem_region(0x80060000, 0x60); + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem) { + size = res_mem->end - res_mem->start + 1; + release_mem_region(res_mem->start, size); + } + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res_mem) { + size = res_mem->end - res_mem->start + 1; + release_mem_region(res_mem->start, size); + } + iounmap(priv->mccr0_base); + iounmap(priv->mccr1_base); return 0; } static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) { struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *priv = priv(mcp); + u32 mccr0; - priv(mcp)->mccr0 = Ser4MCCR0; - priv(mcp)->mccr1 = Ser4MCCR1; - Ser4MCCR0 &= ~MCCR0_MCE; + mccr0 = priv->mccr0 & ~MCCR0_MCE; + __raw_writel(mccr0, priv->mccr0_base + MCCR0); return 0; } @@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) static int mcp_sa11x0_resume(struct platform_device *dev) { struct mcp *mcp = platform_get_drvdata(dev); + struct mcp_sa11x0 *priv = priv(mcp); - Ser4MCCR1 = priv(mcp)->mccr1; - Ser4MCCR0 = priv(mcp)->mccr0; + __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0); + __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1); return 0; } @@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = { .resume = mcp_sa11x0_resume, .driver = { .name = "sa11x0-mcp", + .owner = THIS_MODULE, }, }; /* * This needs re-working */ -static int __init mcp_sa11x0_init(void) -{ - return platform_driver_register(&mcp_sa11x0_driver); -} - -static void __exit mcp_sa11x0_exit(void) -{ - platform_driver_unregister(&mcp_sa11x0_driver); -} - -module_init(mcp_sa11x0_init); -module_exit(mcp_sa11x0_exit); +module_platform_driver(mcp_sa11x0_driver); MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 3f565ef3e149..68ac2c55d5ae 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -503,19 +503,13 @@ static void omap_usbhs_init(struct device *dev) spin_lock_irqsave(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { - gpio_request(pdata->ehci_data->reset_gpio_port[0], - "USB1 PHY reset"); - gpio_direction_output - (pdata->ehci_data->reset_gpio_port[0], 0); - } + if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) + gpio_request_one(pdata->ehci_data->reset_gpio_port[0], + GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { - gpio_request(pdata->ehci_data->reset_gpio_port[1], - "USB2 PHY reset"); - gpio_direction_output - (pdata->ehci_data->reset_gpio_port[1], 0); - } + if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) + gpio_request_one(pdata->ehci_data->reset_gpio_port[1], + GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index aed0d2a9b032..3927c17e4175 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -249,17 +249,7 @@ static struct platform_driver pcf50633_adc_driver = { .remove = __devexit_p(pcf50633_adc_remove), }; -static int __init pcf50633_adc_init(void) -{ - return platform_driver_register(&pcf50633_adc_driver); -} -module_init(pcf50633_adc_init); - -static void __exit pcf50633_adc_exit(void) -{ - platform_driver_unregister(&pcf50633_adc_driver); -} -module_exit(pcf50633_adc_exit); +module_platform_driver(pcf50633_adc_driver); MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); MODULE_DESCRIPTION("PCF50633 adc driver"); diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c new file mode 100644 index 000000000000..e075c113eec6 --- /dev/null +++ b/drivers/mfd/s5m-core.c @@ -0,0 +1,176 @@ +/* + * s5m87xx.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/pm_runtime.h> +#include <linux/mutex.h> +#include <linux/mfd/core.h> +#include <linux/mfd/s5m87xx/s5m-core.h> +#include <linux/mfd/s5m87xx/s5m-pmic.h> +#include <linux/mfd/s5m87xx/s5m-rtc.h> +#include <linux/regmap.h> + +static struct mfd_cell s5m87xx_devs[] = { + { + .name = "s5m8767-pmic", + }, { + .name = "s5m-rtc", + }, +}; + +int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest) +{ + return regmap_read(s5m87xx->regmap, reg, dest); +} +EXPORT_SYMBOL_GPL(s5m_reg_read); + +int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf) +{ + return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);; +} +EXPORT_SYMBOL_GPL(s5m_bulk_read); + +int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value) +{ + return regmap_write(s5m87xx->regmap, reg, value); +} +EXPORT_SYMBOL_GPL(s5m_reg_write); + +int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf) +{ + return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16)); +} +EXPORT_SYMBOL_GPL(s5m_bulk_write); + +int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask) +{ + return regmap_update_bits(s5m87xx->regmap, reg, mask, val); +} +EXPORT_SYMBOL_GPL(s5m_reg_update); + +static struct regmap_config s5m_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int s5m87xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct s5m_platform_data *pdata = i2c->dev.platform_data; + struct s5m87xx_dev *s5m87xx; + int ret = 0; + int error; + + s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL); + if (s5m87xx == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, s5m87xx); + s5m87xx->dev = &i2c->dev; + s5m87xx->i2c = i2c; + s5m87xx->irq = i2c->irq; + s5m87xx->type = id->driver_data; + + if (pdata) { + s5m87xx->device_type = pdata->device_type; + s5m87xx->ono = pdata->ono; + s5m87xx->irq_base = pdata->irq_base; + s5m87xx->wakeup = pdata->wakeup; + } + + s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config); + if (IS_ERR(s5m87xx->regmap)) { + error = PTR_ERR(s5m87xx->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + error); + goto err; + } + + s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); + i2c_set_clientdata(s5m87xx->rtc, s5m87xx); + + if (pdata->cfg_pmic_irq) + pdata->cfg_pmic_irq(); + + s5m_irq_init(s5m87xx); + + pm_runtime_set_active(s5m87xx->dev); + + ret = mfd_add_devices(s5m87xx->dev, -1, + s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs), + NULL, 0); + + if (ret < 0) + goto err; + + return ret; + +err: + mfd_remove_devices(s5m87xx->dev); + s5m_irq_exit(s5m87xx); + i2c_unregister_device(s5m87xx->rtc); + regmap_exit(s5m87xx->regmap); + kfree(s5m87xx); + return ret; +} + +static int s5m87xx_i2c_remove(struct i2c_client *i2c) +{ + struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c); + + mfd_remove_devices(s5m87xx->dev); + s5m_irq_exit(s5m87xx); + i2c_unregister_device(s5m87xx->rtc); + regmap_exit(s5m87xx->regmap); + kfree(s5m87xx); + return 0; +} + +static const struct i2c_device_id s5m87xx_i2c_id[] = { + { "s5m87xx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id); + +static struct i2c_driver s5m87xx_i2c_driver = { + .driver = { + .name = "s5m87xx", + .owner = THIS_MODULE, + }, + .probe = s5m87xx_i2c_probe, + .remove = s5m87xx_i2c_remove, + .id_table = s5m87xx_i2c_id, +}; + +static int __init s5m87xx_i2c_init(void) +{ + return i2c_add_driver(&s5m87xx_i2c_driver); +} + +subsys_initcall(s5m87xx_i2c_init); + +static void __exit s5m87xx_i2c_exit(void) +{ + i2c_del_driver(&s5m87xx_i2c_driver); +} +module_exit(s5m87xx_i2c_exit); + +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("Core support for the S5M MFD"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c new file mode 100644 index 000000000000..de76dfb6f0ad --- /dev/null +++ b/drivers/mfd/s5m-irq.c @@ -0,0 +1,487 @@ +/* + * s5m-irq.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * http://www.samsung.com + * + * 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 <linux/device.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mfd/s5m87xx/s5m-core.h> + +struct s5m_irq_data { + int reg; + int mask; +}; + +static struct s5m_irq_data s5m8767_irqs[] = { + [S5M8767_IRQ_PWRR] = { + .reg = 1, + .mask = S5M8767_IRQ_PWRR_MASK, + }, + [S5M8767_IRQ_PWRF] = { + .reg = 1, + .mask = S5M8767_IRQ_PWRF_MASK, + }, + [S5M8767_IRQ_PWR1S] = { + .reg = 1, + .mask = S5M8767_IRQ_PWR1S_MASK, + }, + [S5M8767_IRQ_JIGR] = { + .reg = 1, + .mask = S5M8767_IRQ_JIGR_MASK, + }, + [S5M8767_IRQ_JIGF] = { + .reg = 1, + .mask = S5M8767_IRQ_JIGF_MASK, + }, + [S5M8767_IRQ_LOWBAT2] = { + .reg = 1, + .mask = S5M8767_IRQ_LOWBAT2_MASK, + }, + [S5M8767_IRQ_LOWBAT1] = { + .reg = 1, + .mask = S5M8767_IRQ_LOWBAT1_MASK, + }, + [S5M8767_IRQ_MRB] = { + .reg = 2, + .mask = S5M8767_IRQ_MRB_MASK, + }, + [S5M8767_IRQ_DVSOK2] = { + .reg = 2, + .mask = S5M8767_IRQ_DVSOK2_MASK, + }, + [S5M8767_IRQ_DVSOK3] = { + .reg = 2, + .mask = S5M8767_IRQ_DVSOK3_MASK, + }, + [S5M8767_IRQ_DVSOK4] = { + .reg = 2, + .mask = S5M8767_IRQ_DVSOK4_MASK, + }, + [S5M8767_IRQ_RTC60S] = { + .reg = 3, + .mask = S5M8767_IRQ_RTC60S_MASK, + }, + [S5M8767_IRQ_RTCA1] = { + .reg = 3, + .mask = S5M8767_IRQ_RTCA1_MASK, + }, + [S5M8767_IRQ_RTCA2] = { + .reg = 3, + .mask = S5M8767_IRQ_RTCA2_MASK, + }, + [S5M8767_IRQ_SMPL] = { + .reg = 3, + .mask = S5M8767_IRQ_SMPL_MASK, + }, + [S5M8767_IRQ_RTC1S] = { + .reg = 3, + .mask = S5M8767_IRQ_RTC1S_MASK, + }, + [S5M8767_IRQ_WTSR] = { + .reg = 3, + .mask = S5M8767_IRQ_WTSR_MASK, + }, +}; + +static struct s5m_irq_data s5m8763_irqs[] = { + [S5M8763_IRQ_DCINF] = { + .reg = 1, + .mask = S5M8763_IRQ_DCINF_MASK, + }, + [S5M8763_IRQ_DCINR] = { + .reg = 1, + .mask = S5M8763_IRQ_DCINR_MASK, + }, + [S5M8763_IRQ_JIGF] = { + .reg = 1, + .mask = S5M8763_IRQ_JIGF_MASK, + }, + [S5M8763_IRQ_JIGR] = { + .reg = 1, + .mask = S5M8763_IRQ_JIGR_MASK, + }, + [S5M8763_IRQ_PWRONF] = { + .reg = 1, + .mask = S5M8763_IRQ_PWRONF_MASK, + }, + [S5M8763_IRQ_PWRONR] = { + .reg = 1, + .mask = S5M8763_IRQ_PWRONR_MASK, + }, + [S5M8763_IRQ_WTSREVNT] = { + .reg = 2, + .mask = S5M8763_IRQ_WTSREVNT_MASK, + }, + [S5M8763_IRQ_SMPLEVNT] = { + .reg = 2, + .mask = S5M8763_IRQ_SMPLEVNT_MASK, + }, + [S5M8763_IRQ_ALARM1] = { + .reg = 2, + .mask = S5M8763_IRQ_ALARM1_MASK, + }, + [S5M8763_IRQ_ALARM0] = { + .reg = 2, + .mask = S5M8763_IRQ_ALARM0_MASK, + }, + [S5M8763_IRQ_ONKEY1S] = { + .reg = 3, + .mask = S5M8763_IRQ_ONKEY1S_MASK, + }, + [S5M8763_IRQ_TOPOFFR] = { + .reg = 3, + .mask = S5M8763_IRQ_TOPOFFR_MASK, + }, + [S5M8763_IRQ_DCINOVPR] = { + .reg = 3, + .mask = S5M8763_IRQ_DCINOVPR_MASK, + }, + [S5M8763_IRQ_CHGRSTF] = { + .reg = 3, + .mask = S5M8763_IRQ_CHGRSTF_MASK, + }, + [S5M8763_IRQ_DONER] = { + .reg = 3, + .mask = S5M8763_IRQ_DONER_MASK, + }, + [S5M8763_IRQ_CHGFAULT] = { + .reg = 3, + .mask = S5M8763_IRQ_CHGFAULT_MASK, + }, + [S5M8763_IRQ_LOBAT1] = { + .reg = 4, + .mask = S5M8763_IRQ_LOBAT1_MASK, + }, + [S5M8763_IRQ_LOBAT2] = { + .reg = 4, + .mask = S5M8763_IRQ_LOBAT2_MASK, + }, +}; + +static inline struct s5m_irq_data * +irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq) +{ + return &s5m8767_irqs[irq - s5m87xx->irq_base]; +} + +static void s5m8767_irq_lock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + + mutex_lock(&s5m87xx->irqlock); +} + +static void s5m8767_irq_sync_unlock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + int i; + + for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) { + if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) { + s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i]; + s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i, + s5m87xx->irq_masks_cur[i]); + } + } + + mutex_unlock(&s5m87xx->irqlock); +} + +static void s5m8767_irq_unmask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; +} + +static void s5m8767_irq_mask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; +} + +static struct irq_chip s5m8767_irq_chip = { + .name = "s5m8767", + .irq_bus_lock = s5m8767_irq_lock, + .irq_bus_sync_unlock = s5m8767_irq_sync_unlock, + .irq_mask = s5m8767_irq_mask, + .irq_unmask = s5m8767_irq_unmask, +}; + +static inline struct s5m_irq_data * +irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq) +{ + return &s5m8763_irqs[irq - s5m87xx->irq_base]; +} + +static void s5m8763_irq_lock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + + mutex_lock(&s5m87xx->irqlock); +} + +static void s5m8763_irq_sync_unlock(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + int i; + + for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) { + if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) { + s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i]; + s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i, + s5m87xx->irq_masks_cur[i]); + } + } + + mutex_unlock(&s5m87xx->irqlock); +} + +static void s5m8763_irq_unmask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; +} + +static void s5m8763_irq_mask(struct irq_data *data) +{ + struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data); + struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx, + data->irq); + + s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; +} + +static struct irq_chip s5m8763_irq_chip = { + .name = "s5m8763", + .irq_bus_lock = s5m8763_irq_lock, + .irq_bus_sync_unlock = s5m8763_irq_sync_unlock, + .irq_mask = s5m8763_irq_mask, + .irq_unmask = s5m8763_irq_unmask, +}; + + +static irqreturn_t s5m8767_irq_thread(int irq, void *data) +{ + struct s5m87xx_dev *s5m87xx = data; + u8 irq_reg[NUM_IRQ_REGS-1]; + int ret; + int i; + + + ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1, + NUM_IRQ_REGS - 1, irq_reg); + if (ret < 0) { + dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n", + ret); + return IRQ_NONE; + } + + for (i = 0; i < NUM_IRQ_REGS - 1; i++) + irq_reg[i] &= ~s5m87xx->irq_masks_cur[i]; + + for (i = 0; i < S5M8767_IRQ_NR; i++) { + if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask) + handle_nested_irq(s5m87xx->irq_base + i); + } + + return IRQ_HANDLED; +} + +static irqreturn_t s5m8763_irq_thread(int irq, void *data) +{ + struct s5m87xx_dev *s5m87xx = data; + u8 irq_reg[NUM_IRQ_REGS]; + int ret; + int i; + + ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1, + NUM_IRQ_REGS, irq_reg); + if (ret < 0) { + dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n", + ret); + return IRQ_NONE; + } + + for (i = 0; i < NUM_IRQ_REGS; i++) + irq_reg[i] &= ~s5m87xx->irq_masks_cur[i]; + + for (i = 0; i < S5M8763_IRQ_NR; i++) { + if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask) + handle_nested_irq(s5m87xx->irq_base + i); + } + + return IRQ_HANDLED; +} + +int s5m_irq_resume(struct s5m87xx_dev *s5m87xx) +{ + if (s5m87xx->irq && s5m87xx->irq_base){ + switch (s5m87xx->device_type) { + case S5M8763X: + s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx); + break; + case S5M8767X: + s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx); + break; + default: + break; + + } + } + return 0; +} + +int s5m_irq_init(struct s5m87xx_dev *s5m87xx) +{ + int i; + int cur_irq; + int ret = 0; + int type = s5m87xx->device_type; + + if (!s5m87xx->irq) { + dev_warn(s5m87xx->dev, + "No interrupt specified, no interrupts\n"); + s5m87xx->irq_base = 0; + return 0; + } + + if (!s5m87xx->irq_base) { + dev_err(s5m87xx->dev, + "No interrupt base specified, no interrupts\n"); + return 0; + } + + mutex_init(&s5m87xx->irqlock); + + switch (type) { + case S5M8763X: + for (i = 0; i < NUM_IRQ_REGS; i++) { + s5m87xx->irq_masks_cur[i] = 0xff; + s5m87xx->irq_masks_cache[i] = 0xff; + s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i, + 0xff); + } + + s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff); + s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff); + + for (i = 0; i < S5M8763_IRQ_NR; i++) { + cur_irq = i + s5m87xx->irq_base; + irq_set_chip_data(cur_irq, s5m87xx); + irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip, + handle_edge_irq); + irq_set_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + irq_set_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(s5m87xx->irq, NULL, + s5m8763_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "s5m87xx-irq", s5m87xx); + if (ret) { + dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n", + s5m87xx->irq, ret); + return ret; + } + break; + case S5M8767X: + for (i = 0; i < NUM_IRQ_REGS - 1; i++) { + s5m87xx->irq_masks_cur[i] = 0xff; + s5m87xx->irq_masks_cache[i] = 0xff; + s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i, + 0xff); + } + for (i = 0; i < S5M8767_IRQ_NR; i++) { + cur_irq = i + s5m87xx->irq_base; + irq_set_chip_data(cur_irq, s5m87xx); + if (ret) { + dev_err(s5m87xx->dev, + "Failed to irq_set_chip_data %d: %d\n", + s5m87xx->irq, ret); + return ret; + } + + irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip, + handle_edge_irq); + irq_set_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + irq_set_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(s5m87xx->irq, NULL, + s5m8767_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "s5m87xx-irq", s5m87xx); + if (ret) { + dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n", + s5m87xx->irq, ret); + return ret; + } + break; + default: + break; + } + + if (!s5m87xx->ono) + return 0; + + switch (type) { + case S5M8763X: + ret = request_threaded_irq(s5m87xx->ono, NULL, + s5m8763_irq_thread, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "s5m87xx-ono", + s5m87xx); + break; + case S5M8767X: + ret = request_threaded_irq(s5m87xx->ono, NULL, + s5m8767_irq_thread, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "s5m87xx-ono", s5m87xx); + break; + default: + break; + } + + if (ret) + dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n", + s5m87xx->ono, ret); + + return 0; +} + +void s5m_irq_exit(struct s5m87xx_dev *s5m87xx) +{ + if (s5m87xx->ono) + free_irq(s5m87xx->ono, s5m87xx); + + if (s5m87xx->irq) + free_irq(s5m87xx->irq, s5m87xx); +} diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index df3702c1756d..f4d86117f44a 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1720,7 +1720,7 @@ static int sm501_plat_remove(struct platform_device *dev) return 0; } -static struct pci_device_id sm501_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = { { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { 0, }, }; diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c new file mode 100644 index 000000000000..373f423b1181 --- /dev/null +++ b/drivers/mfd/stmpe-i2c.c @@ -0,0 +1,109 @@ +/* + * ST Microelectronics MFD: stmpe's i2c client specific driver + * + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) ST Microelectronics SA 2011 + * + * License Terms: GNU General Public License, version 2 + * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson + * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include "stmpe.h" + +static int i2c_reg_read(struct stmpe *stmpe, u8 reg) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_read_byte_data(i2c, reg); +} + +static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_write_byte_data(i2c, reg, val); +} + +static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_read_i2c_block_data(i2c, reg, length, values); +} + +static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length, + const u8 *values) +{ + struct i2c_client *i2c = stmpe->client; + + return i2c_smbus_write_i2c_block_data(i2c, reg, length, values); +} + +static struct stmpe_client_info i2c_ci = { + .read_byte = i2c_reg_read, + .write_byte = i2c_reg_write, + .read_block = i2c_block_read, + .write_block = i2c_block_write, +}; + +static int __devinit +stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + i2c_ci.data = (void *)id; + i2c_ci.irq = i2c->irq; + i2c_ci.client = i2c; + i2c_ci.dev = &i2c->dev; + + return stmpe_probe(&i2c_ci, id->driver_data); +} + +static int __devexit stmpe_i2c_remove(struct i2c_client *i2c) +{ + struct stmpe *stmpe = dev_get_drvdata(&i2c->dev); + + return stmpe_remove(stmpe); +} + +static const struct i2c_device_id stmpe_i2c_id[] = { + { "stmpe610", STMPE610 }, + { "stmpe801", STMPE801 }, + { "stmpe811", STMPE811 }, + { "stmpe1601", STMPE1601 }, + { "stmpe2401", STMPE2401 }, + { "stmpe2403", STMPE2403 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, stmpe_id); + +static struct i2c_driver stmpe_i2c_driver = { + .driver.name = "stmpe-i2c", + .driver.owner = THIS_MODULE, +#ifdef CONFIG_PM + .driver.pm = &stmpe_dev_pm_ops, +#endif + .probe = stmpe_i2c_probe, + .remove = __devexit_p(stmpe_i2c_remove), + .id_table = stmpe_i2c_id, +}; + +static int __init stmpe_init(void) +{ + return i2c_add_driver(&stmpe_i2c_driver); +} +subsys_initcall(stmpe_init); + +static void __exit stmpe_exit(void) +{ + i2c_del_driver(&stmpe_i2c_driver); +} +module_exit(stmpe_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver"); +MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>"); diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c new file mode 100644 index 000000000000..b58c43c7ea93 --- /dev/null +++ b/drivers/mfd/stmpe-spi.c @@ -0,0 +1,150 @@ +/* + * ST Microelectronics MFD: stmpe's spi client specific driver + * + * Copyright (C) ST Microelectronics SA 2011 + * + * License Terms: GNU General Public License, version 2 + * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics + */ + +#include <linux/spi/spi.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include "stmpe.h" + +#define READ_CMD (1 << 7) + +static int spi_reg_read(struct stmpe *stmpe, u8 reg) +{ + struct spi_device *spi = stmpe->client; + int status = spi_w8r16(spi, reg | READ_CMD); + + return (status < 0) ? status : status >> 8; +} + +static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val) +{ + struct spi_device *spi = stmpe->client; + u16 cmd = (val << 8) | reg; + + return spi_write(spi, (const u8 *)&cmd, 2); +} + +static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values) +{ + int ret, i; + + for (i = 0; i < length; i++) { + ret = spi_reg_read(stmpe, reg + i); + if (ret < 0) + return ret; + *(values + i) = ret; + } + + return 0; +} + +static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length, + const u8 *values) +{ + int ret = 0, i; + + for (i = length; i > 0; i--, reg++) { + ret = spi_reg_write(stmpe, reg, *(values + i - 1)); + if (ret < 0) + return ret; + } + + return ret; +} + +static void spi_init(struct stmpe *stmpe) +{ + struct spi_device *spi = stmpe->client; + + spi->bits_per_word = 8; + + /* This register is only present for stmpe811 */ + if (stmpe->variant->id_val == 0x0811) + spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode); + + if (spi_setup(spi) < 0) + dev_dbg(&spi->dev, "spi_setup failed\n"); +} + +static struct stmpe_client_info spi_ci = { + .read_byte = spi_reg_read, + .write_byte = spi_reg_write, + .read_block = spi_block_read, + .write_block = spi_block_write, + .init = spi_init, +}; + +static int __devinit +stmpe_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + + /* don't exceed max specified rate - 1MHz - Limitation of STMPE */ + if (spi->max_speed_hz > 1000000) { + dev_dbg(&spi->dev, "f(sample) %d KHz?\n", + (spi->max_speed_hz/1000)); + return -EINVAL; + } + + spi_ci.irq = spi->irq; + spi_ci.client = spi; + spi_ci.dev = &spi->dev; + + return stmpe_probe(&spi_ci, id->driver_data); +} + +static int __devexit stmpe_spi_remove(struct spi_device *spi) +{ + struct stmpe *stmpe = dev_get_drvdata(&spi->dev); + + return stmpe_remove(stmpe); +} + +static const struct spi_device_id stmpe_spi_id[] = { + { "stmpe610", STMPE610 }, + { "stmpe801", STMPE801 }, + { "stmpe811", STMPE811 }, + { "stmpe1601", STMPE1601 }, + { "stmpe2401", STMPE2401 }, + { "stmpe2403", STMPE2403 }, + { } +}; +MODULE_DEVICE_TABLE(spi, stmpe_id); + +static struct spi_driver stmpe_spi_driver = { + .driver = { + .name = "stmpe-spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &stmpe_dev_pm_ops, +#endif + }, + .probe = stmpe_spi_probe, + .remove = __devexit_p(stmpe_spi_remove), + .id_table = stmpe_spi_id, +}; + +static int __init stmpe_init(void) +{ + return spi_register_driver(&stmpe_spi_driver); +} +subsys_initcall(stmpe_init); + +static void __exit stmpe_exit(void) +{ + spi_unregister_driver(&stmpe_spi_driver); +} +module_exit(stmpe_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver"); +MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 2963689cf45c..e07947e56b2a 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1,18 +1,20 @@ /* + * ST Microelectronics MFD: stmpe's driver + * * Copyright (C) ST-Ericsson SA 2010 * * License Terms: GNU General Public License, version 2 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson */ +#include <linux/gpio.h> +#include <linux/export.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/pm.h> #include <linux/slab.h> -#include <linux/i2c.h> #include <linux/mfd/core.h> -#include <linux/mfd/stmpe.h> #include "stmpe.h" static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) @@ -29,10 +31,9 @@ static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg) { int ret; - ret = i2c_smbus_read_byte_data(stmpe->i2c, reg); + ret = stmpe->ci->read_byte(stmpe, reg); if (ret < 0) - dev_err(stmpe->dev, "failed to read reg %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to read reg %#x: %d\n", reg, ret); dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret); @@ -45,10 +46,9 @@ static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val) dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val); - ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val); + ret = stmpe->ci->write_byte(stmpe, reg, val); if (ret < 0) - dev_err(stmpe->dev, "failed to write reg %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to write reg %#x: %d\n", reg, ret); return ret; } @@ -72,10 +72,9 @@ static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length, { int ret; - ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values); + ret = stmpe->ci->read_block(stmpe, reg, length, values); if (ret < 0) - dev_err(stmpe->dev, "failed to read regs %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to read regs %#x: %d\n", reg, ret); dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret); stmpe_dump_bytes("stmpe rd: ", values, length); @@ -91,11 +90,9 @@ static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length, dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length); stmpe_dump_bytes("stmpe wr: ", values, length); - ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length, - values); + ret = stmpe->ci->write_block(stmpe, reg, length, values); if (ret < 0) - dev_err(stmpe->dev, "failed to write regs %#x: %d\n", - reg, ret); + dev_err(stmpe->dev, "failed to write regs %#x: %d\n", reg, ret); return ret; } @@ -245,12 +242,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block) u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB]; int af_bits = variant->af_bits; int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8); - int afperreg = 8 / af_bits; int mask = (1 << af_bits) - 1; u8 regs[numregs]; - int af; - int ret; + int af, afperreg, ret; + + if (!variant->get_altfunc) + return 0; + afperreg = 8 / af_bits; mutex_lock(&stmpe->lock); ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO); @@ -325,7 +324,51 @@ static struct mfd_cell stmpe_keypad_cell = { }; /* - * Touchscreen (STMPE811) + * STMPE801 + */ +static const u8 stmpe801_regs[] = { + [STMPE_IDX_CHIP_ID] = STMPE801_REG_CHIP_ID, + [STMPE_IDX_ICR_LSB] = STMPE801_REG_SYS_CTRL, + [STMPE_IDX_GPMR_LSB] = STMPE801_REG_GPIO_MP_STA, + [STMPE_IDX_GPSR_LSB] = STMPE801_REG_GPIO_SET_PIN, + [STMPE_IDX_GPCR_LSB] = STMPE801_REG_GPIO_SET_PIN, + [STMPE_IDX_GPDR_LSB] = STMPE801_REG_GPIO_DIR, + [STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN, + [STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA, + +}; + +static struct stmpe_variant_block stmpe801_blocks[] = { + { + .cell = &stmpe_gpio_cell, + .irq = 0, + .block = STMPE_BLOCK_GPIO, + }, +}; + +static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks, + bool enable) +{ + if (blocks & STMPE_BLOCK_GPIO) + return 0; + else + return -EINVAL; +} + +static struct stmpe_variant_info stmpe801 = { + .name = "stmpe801", + .id_val = STMPE801_ID, + .id_mask = 0xffff, + .num_gpios = 8, + .regs = stmpe801_regs, + .blocks = stmpe801_blocks, + .num_blocks = ARRAY_SIZE(stmpe801_blocks), + .num_irqs = STMPE801_NR_INTERNAL_IRQS, + .enable = stmpe801_enable, +}; + +/* + * Touchscreen (STMPE811 or STMPE610) */ static struct resource stmpe_ts_resources[] = { @@ -350,7 +393,7 @@ static struct mfd_cell stmpe_ts_cell = { }; /* - * STMPE811 + * STMPE811 or STMPE610 */ static const u8 stmpe811_regs[] = { @@ -421,6 +464,21 @@ static struct stmpe_variant_info stmpe811 = { .get_altfunc = stmpe811_get_altfunc, }; +/* Similar to 811, except number of gpios */ +static struct stmpe_variant_info stmpe610 = { + .name = "stmpe610", + .id_val = 0x0811, + .id_mask = 0xffff, + .num_gpios = 6, + .af_bits = 1, + .regs = stmpe811_regs, + .blocks = stmpe811_blocks, + .num_blocks = ARRAY_SIZE(stmpe811_blocks), + .num_irqs = STMPE811_NR_INTERNAL_IRQS, + .enable = stmpe811_enable, + .get_altfunc = stmpe811_get_altfunc, +}; + /* * STMPE1601 */ @@ -655,6 +713,8 @@ static struct stmpe_variant_info stmpe2403 = { }; static struct stmpe_variant_info *stmpe_variant_info[] = { + [STMPE610] = &stmpe610, + [STMPE801] = &stmpe801, [STMPE811] = &stmpe811, [STMPE1601] = &stmpe1601, [STMPE2401] = &stmpe2401, @@ -671,6 +731,11 @@ static irqreturn_t stmpe_irq(int irq, void *data) int ret; int i; + if (variant->id_val == STMPE801_ID) { + handle_nested_irq(stmpe->irq_base); + return IRQ_HANDLED; + } + ret = stmpe_block_read(stmpe, israddr, num, isr); if (ret < 0) return IRQ_NONE; @@ -757,14 +822,17 @@ static struct irq_chip stmpe_irq_chip = { static int __devinit stmpe_irq_init(struct stmpe *stmpe) { + struct irq_chip *chip = NULL; int num_irqs = stmpe->variant->num_irqs; int base = stmpe->irq_base; int irq; + if (stmpe->variant->id_val != STMPE801_ID) + chip = &stmpe_irq_chip; + for (irq = base; irq < base + num_irqs; irq++) { irq_set_chip_data(irq, stmpe); - irq_set_chip_and_handler(irq, &stmpe_irq_chip, - handle_edge_irq); + irq_set_chip_and_handler(irq, chip, handle_edge_irq); irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); @@ -796,7 +864,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) unsigned int irq_trigger = stmpe->pdata->irq_trigger; int autosleep_timeout = stmpe->pdata->autosleep_timeout; struct stmpe_variant_info *variant = stmpe->variant; - u8 icr = STMPE_ICR_LSB_GIM; + u8 icr; unsigned int id; u8 data[2]; int ret; @@ -819,16 +887,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe) if (ret) return ret; - if (irq_trigger == IRQF_TRIGGER_FALLING || - irq_trigger == IRQF_TRIGGER_RISING) - icr |= STMPE_ICR_LSB_EDGE; + if (id == STMPE801_ID) + icr = STMPE801_REG_SYS_CTRL_INT_EN; + else + icr = STMPE_ICR_LSB_GIM; + + /* STMPE801 doesn't support Edge interrupts */ + if (id != STMPE801_ID) { + if (irq_trigger == IRQF_TRIGGER_FALLING || + irq_trigger == IRQF_TRIGGER_RISING) + icr |= STMPE_ICR_LSB_EDGE; + } if (irq_trigger == IRQF_TRIGGER_RISING || - irq_trigger == IRQF_TRIGGER_HIGH) - icr |= STMPE_ICR_LSB_HIGH; + irq_trigger == IRQF_TRIGGER_HIGH) { + if (id == STMPE801_ID) + icr |= STMPE801_REG_SYS_CTRL_INT_HI; + else + icr |= STMPE_ICR_LSB_HIGH; + } - if (stmpe->pdata->irq_invert_polarity) - icr ^= STMPE_ICR_LSB_HIGH; + if (stmpe->pdata->irq_invert_polarity) { + if (id == STMPE801_ID) + icr ^= STMPE801_REG_SYS_CTRL_INT_HI; + else + icr ^= STMPE_ICR_LSB_HIGH; + } if (stmpe->pdata->autosleep) { ret = stmpe_autosleep(stmpe, autosleep_timeout); @@ -873,32 +957,10 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe) return ret; } -#ifdef CONFIG_PM -static int stmpe_suspend(struct device *dev) -{ - struct i2c_client *i2c = to_i2c_client(dev); - - if (device_may_wakeup(&i2c->dev)) - enable_irq_wake(i2c->irq); - - return 0; -} - -static int stmpe_resume(struct device *dev) -{ - struct i2c_client *i2c = to_i2c_client(dev); - - if (device_may_wakeup(&i2c->dev)) - disable_irq_wake(i2c->irq); - - return 0; -} -#endif - -static int __devinit stmpe_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +/* Called from client specific probe routines */ +int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum) { - struct stmpe_platform_data *pdata = i2c->dev.platform_data; + struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev); struct stmpe *stmpe; int ret; @@ -912,30 +974,43 @@ static int __devinit stmpe_probe(struct i2c_client *i2c, mutex_init(&stmpe->irq_lock); mutex_init(&stmpe->lock); - stmpe->dev = &i2c->dev; - stmpe->i2c = i2c; - + stmpe->dev = ci->dev; + stmpe->client = ci->client; stmpe->pdata = pdata; stmpe->irq_base = pdata->irq_base; - - stmpe->partnum = id->driver_data; - stmpe->variant = stmpe_variant_info[stmpe->partnum]; + stmpe->ci = ci; + stmpe->partnum = partnum; + stmpe->variant = stmpe_variant_info[partnum]; stmpe->regs = stmpe->variant->regs; stmpe->num_gpios = stmpe->variant->num_gpios; + dev_set_drvdata(stmpe->dev, stmpe); - i2c_set_clientdata(i2c, stmpe); + if (ci->init) + ci->init(stmpe); + + if (pdata->irq_over_gpio) { + ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe"); + if (ret) { + dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", + ret); + goto out_free; + } + + stmpe->irq = gpio_to_irq(pdata->irq_gpio); + } else { + stmpe->irq = ci->irq; + } ret = stmpe_chip_init(stmpe); if (ret) - goto out_free; + goto free_gpio; ret = stmpe_irq_init(stmpe); if (ret) - goto out_free; + goto free_gpio; - ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq, - pdata->irq_trigger | IRQF_ONESHOT, - "stmpe", stmpe); + ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq, + pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe); if (ret) { dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret); goto out_removeirq; @@ -951,67 +1026,55 @@ static int __devinit stmpe_probe(struct i2c_client *i2c, out_removedevs: mfd_remove_devices(stmpe->dev); - free_irq(stmpe->i2c->irq, stmpe); + free_irq(stmpe->irq, stmpe); out_removeirq: stmpe_irq_remove(stmpe); +free_gpio: + if (pdata->irq_over_gpio) + gpio_free(pdata->irq_gpio); out_free: kfree(stmpe); return ret; } -static int __devexit stmpe_remove(struct i2c_client *client) +int stmpe_remove(struct stmpe *stmpe) { - struct stmpe *stmpe = i2c_get_clientdata(client); - mfd_remove_devices(stmpe->dev); - free_irq(stmpe->i2c->irq, stmpe); + free_irq(stmpe->irq, stmpe); stmpe_irq_remove(stmpe); + if (stmpe->pdata->irq_over_gpio) + gpio_free(stmpe->pdata->irq_gpio); + kfree(stmpe); return 0; } -static const struct i2c_device_id stmpe_id[] = { - { "stmpe811", STMPE811 }, - { "stmpe1601", STMPE1601 }, - { "stmpe2401", STMPE2401 }, - { "stmpe2403", STMPE2403 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, stmpe_id); - #ifdef CONFIG_PM -static const struct dev_pm_ops stmpe_dev_pm_ops = { - .suspend = stmpe_suspend, - .resume = stmpe_resume, -}; -#endif +static int stmpe_suspend(struct device *dev) +{ + struct stmpe *stmpe = dev_get_drvdata(dev); -static struct i2c_driver stmpe_driver = { - .driver.name = "stmpe", - .driver.owner = THIS_MODULE, -#ifdef CONFIG_PM - .driver.pm = &stmpe_dev_pm_ops, -#endif - .probe = stmpe_probe, - .remove = __devexit_p(stmpe_remove), - .id_table = stmpe_id, -}; + if (device_may_wakeup(dev)) + enable_irq_wake(stmpe->irq); -static int __init stmpe_init(void) -{ - return i2c_add_driver(&stmpe_driver); + return 0; } -subsys_initcall(stmpe_init); -static void __exit stmpe_exit(void) +static int stmpe_resume(struct device *dev) { - i2c_del_driver(&stmpe_driver); + struct stmpe *stmpe = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(stmpe->irq); + + return 0; } -module_exit(stmpe_exit); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("STMPE MFD core driver"); -MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>"); +const struct dev_pm_ops stmpe_dev_pm_ops = { + .suspend = stmpe_suspend, + .resume = stmpe_resume, +}; +#endif diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index e4ee38956583..7b8e13f5b764 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -8,6 +8,14 @@ #ifndef __STMPE_H #define __STMPE_H +#include <linux/device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/stmpe.h> +#include <linux/printk.h> +#include <linux/types.h> + +extern const struct dev_pm_ops stmpe_dev_pm_ops; + #ifdef STMPE_DUMP_BYTES static inline void stmpe_dump_bytes(const char *str, const void *buf, size_t len) @@ -67,11 +75,55 @@ struct stmpe_variant_info { int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout); }; +/** + * struct stmpe_client_info - i2c or spi specific routines/info + * @data: client specific data + * @read_byte: read single byte + * @write_byte: write single byte + * @read_block: read block or multiple bytes + * @write_block: write block or multiple bytes + * @init: client init routine, called during probe + */ +struct stmpe_client_info { + void *data; + int irq; + void *client; + struct device *dev; + int (*read_byte)(struct stmpe *stmpe, u8 reg); + int (*write_byte)(struct stmpe *stmpe, u8 reg, u8 val); + int (*read_block)(struct stmpe *stmpe, u8 reg, u8 len, u8 *values); + int (*write_block)(struct stmpe *stmpe, u8 reg, u8 len, + const u8 *values); + void (*init)(struct stmpe *stmpe); +}; + +int stmpe_probe(struct stmpe_client_info *ci, int partnum); +int stmpe_remove(struct stmpe *stmpe); + #define STMPE_ICR_LSB_HIGH (1 << 2) #define STMPE_ICR_LSB_EDGE (1 << 1) #define STMPE_ICR_LSB_GIM (1 << 0) /* + * STMPE801 + */ +#define STMPE801_ID 0x0108 +#define STMPE801_NR_INTERNAL_IRQS 1 + +#define STMPE801_REG_CHIP_ID 0x00 +#define STMPE801_REG_VERSION_ID 0x02 +#define STMPE801_REG_SYS_CTRL 0x04 +#define STMPE801_REG_GPIO_INT_EN 0x08 +#define STMPE801_REG_GPIO_INT_STA 0x09 +#define STMPE801_REG_GPIO_MP_STA 0x10 +#define STMPE801_REG_GPIO_SET_PIN 0x11 +#define STMPE801_REG_GPIO_DIR 0x12 + +#define STMPE801_REG_SYS_CTRL_RESET (1 << 7) +#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2) +#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0) + +/* * STMPE811 */ @@ -87,6 +139,7 @@ struct stmpe_variant_info { #define STMPE811_REG_CHIP_ID 0x00 #define STMPE811_REG_SYS_CTRL2 0x04 +#define STMPE811_REG_SPI_CFG 0x08 #define STMPE811_REG_INT_CTRL 0x09 #define STMPE811_REG_INT_EN 0x0A #define STMPE811_REG_INT_STA 0x0B diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 91ad21ef7721..2d9e8799e733 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -442,21 +442,7 @@ static struct platform_driver t7l66xb_platform_driver = { /*--------------------------------------------------------------------------*/ -static int __init t7l66xb_init(void) -{ - int retval = 0; - - retval = platform_driver_register(&t7l66xb_platform_driver); - return retval; -} - -static void __exit t7l66xb_exit(void) -{ - platform_driver_unregister(&t7l66xb_platform_driver); -} - -module_init(t7l66xb_init); -module_exit(t7l66xb_exit); +module_platform_driver(t7l66xb_platform_driver); MODULE_DESCRIPTION("Toshiba T7L66XB core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 71bc835324d8..d20a284ad4ba 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -234,19 +234,7 @@ static struct platform_driver tc6387xb_platform_driver = { .resume = tc6387xb_resume, }; - -static int __init tc6387xb_init(void) -{ - return platform_driver_register(&tc6387xb_platform_driver); -} - -static void __exit tc6387xb_exit(void) -{ - platform_driver_unregister(&tc6387xb_platform_driver); -} - -module_init(tc6387xb_init); -module_exit(tc6387xb_exit); +module_platform_driver(tc6387xb_platform_driver); MODULE_DESCRIPTION("Toshiba TC6387XB core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index af9ab0e5ca64..4fb0e6c8e8fe 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c @@ -458,17 +458,7 @@ static struct platform_driver ti_ssp_driver = { } }; -static int __init ti_ssp_init(void) -{ - return platform_driver_register(&ti_ssp_driver); -} -module_init(ti_ssp_init); - -static void __exit ti_ssp_exit(void) -{ - platform_driver_unregister(&ti_ssp_driver); -} -module_exit(ti_ssp_exit); +module_platform_driver(ti_ssp_driver); MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver"); MODULE_AUTHOR("Cyril Chemparathy"); diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 02d65692ceb4..0ba26fb12cf5 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -857,7 +857,7 @@ static void __devexit timb_remove(struct pci_dev *dev) kfree(priv); } -static struct pci_device_id timberdale_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(timberdale_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) }, { 0 } }; diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index a56be931551c..95c0d7978bec 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -215,6 +215,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, int tps65910_irq_exit(struct tps65910 *tps65910) { - free_irq(tps65910->chip_irq, tps65910); + if (tps65910->chip_irq) + free_irq(tps65910->chip_irq, tps65910); return 0; } diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index c1da84bc1573..01cf5012a08f 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); - ret = tps65910_irq_init(tps65910, init_data->irq, init_data); - if (ret < 0) - goto err; + tps65910_irq_init(tps65910, init_data->irq, init_data); kfree(init_data); return ret; err: - mfd_remove_devices(tps65910->dev); kfree(tps65910); kfree(init_data); return ret; @@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c) { struct tps65910 *tps65910 = i2c_get_clientdata(i2c); - mfd_remove_devices(tps65910->dev); tps65910_irq_exit(tps65910); + mfd_remove_devices(tps65910->dev); kfree(tps65910); return 0; diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index 6d71e0d25744..27d3302d56b8 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -111,7 +111,6 @@ static int __devexit tps65912_spi_remove(struct spi_device *spi) static struct spi_driver tps65912_spi_driver = { .driver = { .name = "tps65912", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = tps65912_spi_probe, diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 61e70cfaa774..e04e04ddc15e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -34,6 +34,11 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/device.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/irqdomain.h> #include <linux/regulator/machine.h> @@ -144,6 +149,9 @@ #define TWL_MODULE_LAST TWL4030_MODULE_LAST +#define TWL4030_NR_IRQS 8 +#define TWL6030_NR_IRQS 20 + /* Base Address defns for twl4030_map[] */ /* subchip/slave 0 - USB ID */ @@ -255,6 +263,7 @@ struct twl_client { static struct twl_client twl_modules[TWL_NUM_SLAVES]; +static struct irq_domain domain; /* mapping the module id to slave id and base address */ struct twl_mapping { @@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) int status; unsigned i; struct twl4030_platform_data *pdata = client->dev.platform_data; + struct device_node *node = client->dev.of_node; u8 temp; int ret = 0; + int nr_irqs = TWL4030_NR_IRQS; + + if ((id->driver_data) & TWL6030_CLASS) + nr_irqs = TWL6030_NR_IRQS; + + if (node && !pdata) { + /* + * XXX: Temporary pdata until the information is correctly + * retrieved by every TWL modules from DT. + */ + pdata = devm_kzalloc(&client->dev, + sizeof(struct twl4030_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + } if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); return -EINVAL; } + status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0); + if (IS_ERR_VALUE(status)) { + dev_err(&client->dev, "Fail to allocate IRQ descs\n"); + return status; + } + + pdata->irq_base = status; + pdata->irq_end = pdata->irq_base + nr_irqs; + + domain.irq_base = pdata->irq_base; + domain.nr_irq = nr_irqs; +#ifdef CONFIG_OF_IRQ + domain.of_node = of_node_get(node); + domain.ops = &irq_domain_simple_ops; +#endif + irq_domain_add(&domain); + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); return -EIO; @@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); } - status = add_children(pdata, id->driver_data); +#ifdef CONFIG_OF_DEVICE + if (node) + status = of_platform_populate(node, NULL, NULL, &client->dev); + else +#endif + status = add_children(pdata, id->driver_data); + fail: if (status < 0) twl_remove(client); diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index ae51ab5d0e5d..838ce4eb444e 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -261,17 +261,7 @@ static struct platform_driver twl4030_audio_driver = { }, }; -static int __devinit twl4030_audio_init(void) -{ - return platform_driver_register(&twl4030_audio_driver); -} -module_init(twl4030_audio_init); - -static void __devexit twl4030_audio_exit(void) -{ - platform_driver_unregister(&twl4030_audio_driver); -} -module_exit(twl4030_audio_exit); +module_platform_driver(twl4030_audio_driver); MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 29f11e0765fe..b69bb517b102 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -492,7 +492,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) u8 bytes[4]; } imr; - /* byte[0] gets overwriten as we write ... */ + /* byte[0] gets overwritten as we write ... */ imr.word = cpu_to_le32(agent->imr << 8); agent->imr_change_pending = false; @@ -667,6 +667,7 @@ int twl4030_sih_setup(int module) irq_set_chip_data(irq, agent); irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip, handle_edge_irq); + irq_set_nested_thread(irq, 1); activate_irq(irq); } diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 834f824d3c11..456ecb5ac4fe 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -807,19 +807,7 @@ static struct platform_driver twl4030_madc_driver = { }, }; -static int __init twl4030_madc_init(void) -{ - return platform_driver_register(&twl4030_madc_driver); -} - -module_init(twl4030_madc_init); - -static void __exit twl4030_madc_exit(void) -{ - platform_driver_unregister(&twl4030_madc_driver); -} - -module_exit(twl4030_madc_exit); +module_platform_driver(twl4030_madc_driver); MODULE_DESCRIPTION("TWL4030 ADC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index a764676f0922..d905f5171153 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -34,7 +34,8 @@ static u8 twl4030_start_script_address = 0x2b; #define PWR_P1_SW_EVENTS 0x10 -#define PWR_DEVOFF (1<<0) +#define PWR_DEVOFF (1 << 0) +#define SEQ_OFFSYNC (1 << 0) #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) #define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b) @@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags) return err; } +/* + * In master mode, start the power off sequence. + * After a successful execution, TWL shuts down the power to the SoC + * and all peripherals connected to it. + */ +void twl4030_power_off(void) +{ + int err; + + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF, + TWL4030_PM_MASTER_P1_SW_EVENTS); + if (err) + pr_err("TWL4030 Unable to power off\n"); +} + void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) { int err = 0; int i; struct twl4030_resconfig *resconfig; - u8 address = twl4030_start_script_address; + u8 val, address = twl4030_start_script_address; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, @@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) } } + /* Board has to be wired properly to use this feature */ + if (twl4030_scripts->use_poweroff && !pm_power_off) { + /* Default for SEQ_OFFSYNC is set, lets ensure this */ + err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, + TWL4030_PM_MASTER_CFG_P123_TRANSITION); + if (err) { + pr_warning("TWL4030 Unable to read registers\n"); + + } else if (!(val & SEQ_OFFSYNC)) { + val |= SEQ_OFFSYNC; + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, + TWL4030_PM_MASTER_CFG_P123_TRANSITION); + if (err) { + pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); + goto relock; + } + } + + pm_power_off = twl4030_power_off; + } + +relock: err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, TWL4030_PM_MASTER_PROTECT_KEY); if (err) diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 268f80fd0439..dda86293dc9f 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev) twl6040->audpwron = -EINVAL; if (gpio_is_valid(twl6040->audpwron)) { - ret = gpio_request(twl6040->audpwron, "audpwron"); + ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW, + "audpwron"); if (ret) goto gpio1_err; - - ret = gpio_direction_output(twl6040->audpwron, 0); - if (ret) - goto gpio2_err; } /* codec interrupt */ @@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = { }, }; -static int __devinit twl6040_init(void) -{ - return platform_driver_register(&twl6040_driver); -} -module_init(twl6040_init); - -static void __devexit twl6040_exit(void) -{ - platform_driver_unregister(&twl6040_driver); -} - -module_exit(twl6040_exit); +module_platform_driver(twl6040_driver); MODULE_DESCRIPTION("TWL6040 MFD"); MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index b281217334eb..91c4f25e0e55 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex); static LIST_HEAD(ucb1x00_drivers); static LIST_HEAD(ucb1x00_devices); +static struct mcp_device_id ucb1x00_id[] = { + { "ucb1x00", 0 }, /* auto-detection */ + { "ucb1200", UCB_ID_1200 }, + { "ucb1300", UCB_ID_1300 }, + { "tc35143", UCB_ID_TC35143 }, + { } +}; +MODULE_DEVICE_TABLE(mcp, ucb1x00_id); + /** * ucb1x00_io_set_dir - set IO direction * @ucb: UCB1x00 structure describing chip @@ -527,17 +536,33 @@ static struct class ucb1x00_class = { static int ucb1x00_probe(struct mcp *mcp) { + const struct mcp_device_id *mid; struct ucb1x00 *ucb; struct ucb1x00_driver *drv; + struct ucb1x00_plat_data *pdata; unsigned int id; int ret = -ENODEV; int temp; mcp_enable(mcp); id = mcp_reg_read(mcp, UCB_ID); + mid = mcp_get_device_id(mcp); - if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { - printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); + if (mid && mid->driver_data) { + if (id != mid->driver_data) { + printk(KERN_WARNING "%s wrong ID %04x found: %04x\n", + mid->name, (unsigned int) mid->driver_data, id); + goto err_disable; + } + } else { + mid = &ucb1x00_id[1]; + while (mid->driver_data) { + if (id == mid->driver_data) + break; + mid++; + } + printk(KERN_WARNING "%s ID not found: %04x\n", + ucb1x00_id[0].name, id); goto err_disable; } @@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp) if (!ucb) goto err_disable; - + pdata = mcp->attached_device.platform_data; ucb->dev.class = &ucb1x00_class; ucb->dev.parent = &mcp->attached_device; - dev_set_name(&ucb->dev, "ucb1x00"); + dev_set_name(&ucb->dev, mid->name); spin_lock_init(&ucb->lock); spin_lock_init(&ucb->io_lock); sema_init(&ucb->adc_sem, 1); - ucb->id = id; + ucb->id = mid; ucb->mcp = mcp; ucb->irq = ucb1x00_detect_irq(ucb); if (ucb->irq == NO_IRQ) { - printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); + printk(KERN_ERR "%s: IRQ probe failed\n", mid->name); ret = -ENODEV; goto err_free; } ucb->gpio.base = -1; - if (mcp->gpio_base != 0) { + if (pdata && (pdata->gpio_base >= 0)) { ucb->gpio.label = dev_name(&ucb->dev); - ucb->gpio.base = mcp->gpio_base; + ucb->gpio.base = pdata->gpio_base; ucb->gpio.ngpio = 10; ucb->gpio.set = ucb1x00_gpio_set; ucb->gpio.get = ucb1x00_gpio_get; @@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp) dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, - "UCB1x00", ucb); + mid->name, ucb); if (ret) { - printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", - ucb->irq, ret); + printk(KERN_ERR "%s: unable to grab irq%d: %d\n", + mid->name, ucb->irq, ret); goto err_gpio; } @@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = { .remove = ucb1x00_remove, .suspend = ucb1x00_suspend, .resume = ucb1x00_resume, + .id_table = ucb1x00_id, }; static int __init ucb1x00_init(void) diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 38ffbd50a0d2..40ec3c118868 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; idev->name = "Touchscreen panel"; - idev->id.product = ts->ucb->id; + idev->id.product = ts->ucb->id->driver_data; idev->open = ucb1x00_ts_open; idev->close = ucb1x00_ts_close; diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index d698703dbd46..b73cc15e0081 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c @@ -118,7 +118,7 @@ static void __devexit vx855_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id vx855_pci_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(vx855_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, { 0, } }; diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 0a2b8d41a702..f5e54fae8ada 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -559,6 +559,8 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg, dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n", buf[i], reg + i, reg + i); ret = regmap_write(wm831x->regmap, reg + i, buf[i]); + if (ret != 0) + return ret; } return 0; @@ -1875,7 +1877,6 @@ err_irq: err_regmap: mfd_remove_devices(wm831x->dev); regmap_exit(wm831x->regmap); - kfree(wm831x); return ret; } @@ -1887,7 +1888,6 @@ void wm831x_device_exit(struct wm831x *wm831x) free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x); wm831x_irq_exit(wm831x); regmap_exit(wm831x->regmap); - kfree(wm831x); } int wm831x_device_suspend(struct wm831x *wm831x) diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index ac8da1d439da..cb15609b0a48 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -30,7 +30,7 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, struct wm831x *wm831x; int ret; - wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); + wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) return -ENOMEM; @@ -42,7 +42,6 @@ static int wm831x_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); - kfree(wm831x); return ret; } diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index f4747a4a9a93..bec4d0539160 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -325,11 +325,6 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data) return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data->reg; } -static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data) -{ - return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg; -} - static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, int irq) { @@ -477,8 +472,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); if (primary & WM831X_TCHDATA_INT) handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); - if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT)) - goto out; + primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { int offset = wm831x_irqs[i].reg - 1; diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 8d6a9a969dbc..62ef3254105f 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -30,7 +30,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) type = (enum wm831x_parent)id->driver_data; - wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL); + wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL); if (wm831x == NULL) return -ENOMEM; @@ -45,7 +45,6 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) ret = PTR_ERR(wm831x->regmap); dev_err(wm831x->dev, "Failed to allocate register map: %d\n", ret); - kfree(wm831x); return ret; } @@ -95,7 +94,6 @@ MODULE_DEVICE_TABLE(spi, wm831x_spi_id); static struct spi_driver wm831x_spi_driver = { .driver = { .name = "wm831x", - .bus = &spi_bus_type, .owner = THIS_MODULE, .pm = &wm831x_spi_pm, }, diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index e81cc31e4202..dd1caaac55e4 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -573,6 +573,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq, u16 id1, id2, mask_rev; u16 cust_id, mode, chip_rev; + dev_set_drvdata(wm8350->dev, wm8350); + /* get WM8350 revision and config mode */ ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1); if (ret != 0) { diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 5fe5de166adb..d955faaf27c4 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -63,7 +63,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, struct wm8350 *wm8350; int ret = 0; - wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL); + wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL); if (wm8350 == NULL) return -ENOMEM; @@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, return ret; err: - kfree(wm8350); return ret; } @@ -89,7 +88,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c) struct wm8350 *wm8350 = i2c_get_clientdata(i2c); wm8350_device_exit(wm8350); - kfree(wm8350); return 0; } diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 62b4626f4561..2204893444a6 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -344,7 +344,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, struct wm8400 *wm8400; int ret; - wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL); + wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL); if (wm8400 == NULL) { ret = -ENOMEM; goto err; @@ -353,7 +353,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config); if (IS_ERR(wm8400->regmap)) { ret = PTR_ERR(wm8400->regmap); - goto struct_err; + goto err; } wm8400->dev = &i2c->dev; @@ -367,8 +367,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, map_err: regmap_exit(wm8400->regmap); -struct_err: - kfree(wm8400); err: return ret; } @@ -379,7 +377,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c) wm8400_release(wm8400); regmap_exit(wm8400->regmap); - kfree(wm8400); return 0; } diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 5664696f2d3a..6a1a092db146 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -500,6 +500,14 @@ config USB_SWITCH_FSA9480 stereo and mono audio, video, microphone and UART data to use a common connector port. +config MAX8997_MUIC + tristate "MAX8997 MUIC Support" + depends on MFD_MAX8997 + help + If you say yes here you get support for the MUIC device of + Maxim MAX8997 PMIC. + The MAX8997 MUIC is a USB port accessory detector and switch. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b26495a02554..3e1d80106f04 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -48,3 +48,4 @@ obj-y += lis3lv02d/ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ +obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c index 2208a9d52622..d7a9aa14e5d5 100644 --- a/drivers/misc/ab8500-pwm.c +++ b/drivers/misc/ab8500-pwm.c @@ -8,8 +8,8 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/pwm.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/module.h> /* diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index b1f4563be9ae..701eb600b127 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c @@ -376,20 +376,20 @@ static int blocks; module_param(blocks, int, 0604); MODULE_PARM_DESC(blocks, "max_blocks_to_send"); -static int dump; +static bool dump; module_param(dump, bool, 0604); MODULE_PARM_DESC(dump, "dump_hex_content"); -static int jump = 1; +static bool jump = 1; module_param(jump, bool, 0604); -static int direct = 1; +static bool direct = 1; module_param(direct, bool, 0604); -static int checksum = 1; +static bool checksum = 1; module_param(checksum, bool, 0604); -static int fw_download = 1; +static bool fw_download = 1; module_param(fw_download, bool, 0604); static int block_size = IWMC_SDIO_BLK_SIZE; @@ -398,7 +398,7 @@ module_param(block_size, int, 0404); static int download_trans_blks = IWMC_DEFAULT_TR_BLK; module_param(download_trans_blks, int, 0604); -static int rubbish_barker; +static bool rubbish_barker; module_param(rubbish_barker, bool, 0604); #ifdef CONFIG_IWMC3200TOP_DEBUG diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 29d12a70eb1b..a981e2a42f92 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -111,6 +111,8 @@ static struct kernel_param_ops param_ops_axis = { .get = param_get_int, }; +#define param_check_axis(name, p) param_check_int(name, p) + module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); diff --git a/drivers/misc/max8997-muic.c b/drivers/misc/max8997-muic.c new file mode 100644 index 000000000000..d74ef41aabd5 --- /dev/null +++ b/drivers/misc/max8997-muic.c @@ -0,0 +1,505 @@ +/* + * max8997-muic.c - MAX8997 muic driver for the Maxim 8997 + * + * Copyright (C) 2011 Samsung Electrnoics + * Donggeun Kim <dg77.kim@samsung.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/kobject.h> +#include <linux/mfd/max8997.h> +#include <linux/mfd/max8997-private.h> + +/* MAX8997-MUIC STATUS1 register */ +#define STATUS1_ADC_SHIFT 0 +#define STATUS1_ADCLOW_SHIFT 5 +#define STATUS1_ADCERR_SHIFT 6 +#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) +#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) +#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) + +/* MAX8997-MUIC STATUS2 register */ +#define STATUS2_CHGTYP_SHIFT 0 +#define STATUS2_CHGDETRUN_SHIFT 3 +#define STATUS2_DCDTMR_SHIFT 4 +#define STATUS2_DBCHG_SHIFT 5 +#define STATUS2_VBVOLT_SHIFT 6 +#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) +#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) +#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) +#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT) +#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) + +/* MAX8997-MUIC STATUS3 register */ +#define STATUS3_OVP_SHIFT 2 +#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) + +/* MAX8997-MUIC CONTROL1 register */ +#define COMN1SW_SHIFT 0 +#define COMP2SW_SHIFT 3 +#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) +#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) +#define SW_MASK (COMP2SW_MASK | COMN1SW_MASK) + +#define MAX8997_SW_USB ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT)) +#define MAX8997_SW_AUDIO ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT)) +#define MAX8997_SW_UART ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT)) +#define MAX8997_SW_OPEN ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT)) + +#define MAX8997_ADC_GROUND 0x00 +#define MAX8997_ADC_MHL 0x01 +#define MAX8997_ADC_JIG_USB_1 0x18 +#define MAX8997_ADC_JIG_USB_2 0x19 +#define MAX8997_ADC_DESKDOCK 0x1a +#define MAX8997_ADC_JIG_UART 0x1c +#define MAX8997_ADC_CARDOCK 0x1d +#define MAX8997_ADC_OPEN 0x1f + +struct max8997_muic_irq { + unsigned int irq; + const char *name; +}; + +static struct max8997_muic_irq muic_irqs[] = { + { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" }, + { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" }, + { MAX8997_MUICIRQ_ADC, "muic-ADC" }, + { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" }, + { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" }, + { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" }, + { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" }, + { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" }, + { MAX8997_MUICIRQ_OVP, "muic-over_voltage" }, +}; + +struct max8997_muic_info { + struct device *dev; + struct max8997_dev *iodev; + struct i2c_client *muic; + struct max8997_muic_platform_data *muic_pdata; + + int irq; + struct work_struct irq_work; + + enum max8997_muic_charger_type pre_charger_type; + int pre_adc; + + struct mutex mutex; +}; + +static int max8997_muic_handle_usb(struct max8997_muic_info *info, + enum max8997_muic_usb_type usb_type, bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + if (usb_type == MAX8997_USB_HOST) { + /* switch to USB */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_USB : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + } + + if (mdata->usb_callback) + mdata->usb_callback(usb_type, attached); +out: + return ret; +} + +static void max8997_muic_handle_mhl(struct max8997_muic_info *info, + bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + + if (mdata->mhl_callback) + mdata->mhl_callback(attached); +} + +static int max8997_muic_handle_dock(struct max8997_muic_info *info, + int adc, bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + /* switch to AUDIO */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + + switch (adc) { + case MAX8997_ADC_DESKDOCK: + if (mdata->deskdock_callback) + mdata->deskdock_callback(attached); + break; + case MAX8997_ADC_CARDOCK: + if (mdata->cardock_callback) + mdata->cardock_callback(attached); + break; + default: + break; + } +out: + return ret; +} + +static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, + bool attached) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int ret = 0; + + /* switch to UART */ + ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, + attached ? MAX8997_SW_UART : MAX8997_SW_OPEN, + SW_MASK); + if (ret) { + dev_err(info->dev, "failed to update muic register\n"); + goto out; + } + + if (mdata->uart_callback) + mdata->uart_callback(attached); +out: + return ret; +} + +static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info) +{ + int ret = 0; + + switch (info->pre_adc) { + case MAX8997_ADC_GROUND: + ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); + break; + case MAX8997_ADC_MHL: + max8997_muic_handle_mhl(info, false); + break; + case MAX8997_ADC_JIG_USB_1: + case MAX8997_ADC_JIG_USB_2: + ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false); + break; + case MAX8997_ADC_DESKDOCK: + case MAX8997_ADC_CARDOCK: + ret = max8997_muic_handle_dock(info, info->pre_adc, false); + break; + case MAX8997_ADC_JIG_UART: + ret = max8997_muic_handle_jig_uart(info, false); + break; + default: + break; + } + + return ret; +} + +static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) +{ + int ret = 0; + + switch (adc) { + case MAX8997_ADC_GROUND: + ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); + break; + case MAX8997_ADC_MHL: + max8997_muic_handle_mhl(info, true); + break; + case MAX8997_ADC_JIG_USB_1: + case MAX8997_ADC_JIG_USB_2: + ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true); + break; + case MAX8997_ADC_DESKDOCK: + case MAX8997_ADC_CARDOCK: + ret = max8997_muic_handle_dock(info, adc, true); + break; + case MAX8997_ADC_JIG_UART: + ret = max8997_muic_handle_jig_uart(info, true); + break; + case MAX8997_ADC_OPEN: + ret = max8997_muic_handle_adc_detach(info); + break; + default: + break; + } + + info->pre_adc = adc; + + return ret; +} + +static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, + enum max8997_muic_charger_type charger_type) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + u8 adc; + int ret; + + ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + goto out; + } + + switch (charger_type) { + case MAX8997_CHARGER_TYPE_NONE: + if (mdata->charger_callback) + mdata->charger_callback(false, charger_type); + if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) { + max8997_muic_handle_usb(info, + MAX8997_USB_DEVICE, false); + } + break; + case MAX8997_CHARGER_TYPE_USB: + if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { + max8997_muic_handle_usb(info, + MAX8997_USB_DEVICE, true); + } + if (mdata->charger_callback) + mdata->charger_callback(true, charger_type); + break; + case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: + case MAX8997_CHARGER_TYPE_DEDICATED_CHG: + case MAX8997_CHARGER_TYPE_500MA: + case MAX8997_CHARGER_TYPE_1A: + if (mdata->charger_callback) + mdata->charger_callback(true, charger_type); + break; + default: + break; + } + + info->pre_charger_type = charger_type; +out: + return ret; +} + +static void max8997_muic_irq_work(struct work_struct *work) +{ + struct max8997_muic_info *info = container_of(work, + struct max8997_muic_info, irq_work); + struct max8997_platform_data *pdata = + dev_get_platdata(info->iodev->dev); + u8 status[3]; + u8 adc, chg_type; + + int irq_type = info->irq - pdata->irq_base; + int ret; + + mutex_lock(&info->mutex); + + ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, + 3, status); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + mutex_unlock(&info->mutex); + return; + } + + dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__, + status[0], status[1]); + + switch (irq_type) { + case MAX8997_MUICIRQ_ADC: + adc = status[0] & STATUS1_ADC_MASK; + adc >>= STATUS1_ADC_SHIFT; + + max8997_muic_handle_adc(info, adc); + break; + case MAX8997_MUICIRQ_ChgTyp: + chg_type = status[1] & STATUS2_CHGTYP_MASK; + chg_type >>= STATUS2_CHGTYP_SHIFT; + + max8997_muic_handle_charger_type(info, chg_type); + break; + default: + dev_info(info->dev, "misc interrupt: %s occurred\n", + muic_irqs[irq_type].name); + break; + } + + mutex_unlock(&info->mutex); + + return; +} + +static irqreturn_t max8997_muic_irq_handler(int irq, void *data) +{ + struct max8997_muic_info *info = data; + + dev_dbg(info->dev, "irq:%d\n", irq); + info->irq = irq; + + schedule_work(&info->irq_work); + + return IRQ_HANDLED; +} + +static void max8997_muic_detect_dev(struct max8997_muic_info *info) +{ + int ret; + u8 status[2], adc, chg_type; + + ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, + 2, status); + if (ret) { + dev_err(info->dev, "failed to read muic register\n"); + return; + } + + dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n", + status[0], status[1]); + + adc = status[0] & STATUS1_ADC_MASK; + adc >>= STATUS1_ADC_SHIFT; + + chg_type = status[1] & STATUS2_CHGTYP_MASK; + chg_type >>= STATUS2_CHGTYP_SHIFT; + + max8997_muic_handle_adc(info, adc); + max8997_muic_handle_charger_type(info, chg_type); +} + +static void max8997_initialize_device(struct max8997_muic_info *info) +{ + struct max8997_muic_platform_data *mdata = info->muic_pdata; + int i; + + for (i = 0; i < mdata->num_init_data; i++) { + max8997_write_reg(info->muic, mdata->init_data[i].addr, + mdata->init_data[i].data); + } +} + +static int __devinit max8997_muic_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct max8997_muic_info *info; + int ret, i; + + info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL); + if (!info) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + ret = -ENOMEM; + goto err_kfree; + } + + if (!pdata->muic_pdata) { + dev_err(&pdev->dev, "failed to get platform_data\n"); + ret = -EINVAL; + goto err_pdata; + } + info->muic_pdata = pdata->muic_pdata; + + info->dev = &pdev->dev; + info->iodev = iodev; + info->muic = iodev->muic; + + platform_set_drvdata(pdev, info); + mutex_init(&info->mutex); + + INIT_WORK(&info->irq_work, max8997_muic_irq_work); + + for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { + struct max8997_muic_irq *muic_irq = &muic_irqs[i]; + + ret = request_threaded_irq(pdata->irq_base + muic_irq->irq, + NULL, max8997_muic_irq_handler, + 0, muic_irq->name, + info); + if (ret) { + dev_err(&pdev->dev, + "failed: irq request (IRQ: %d," + " error :%d)\n", + muic_irq->irq, ret); + + for (i = i - 1; i >= 0; i--) + free_irq(muic_irq->irq, info); + + goto err_irq; + } + } + + /* Initialize registers according to platform data */ + max8997_initialize_device(info); + + /* Initial device detection */ + max8997_muic_detect_dev(info); + + return ret; + +err_irq: +err_pdata: + kfree(info); +err_kfree: + return ret; +} + +static int __devexit max8997_muic_remove(struct platform_device *pdev) +{ + struct max8997_muic_info *info = platform_get_drvdata(pdev); + struct max8997_platform_data *pdata = + dev_get_platdata(info->iodev->dev); + int i; + + for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) + free_irq(pdata->irq_base + muic_irqs[i].irq, info); + cancel_work_sync(&info->irq_work); + + kfree(info); + + return 0; +} + +static struct platform_driver max8997_muic_driver = { + .driver = { + .name = "max8997-muic", + .owner = THIS_MODULE, + }, + .probe = max8997_muic_probe, + .remove = __devexit_p(max8997_muic_remove), +}; + +static int __init max8997_muic_init(void) +{ + return platform_driver_register(&max8997_muic_driver); +} +module_init(max8997_muic_init); + +static void __exit max8997_muic_exit(void) +{ + platform_driver_unregister(&max8997_muic_driver); +} +module_exit(max8997_muic_exit); + +MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver"); +MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 12eef393e216..400756ec7c49 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -6,5 +6,4 @@ subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG obj-$(CONFIG_MMC) += core/ obj-$(CONFIG_MMC) += card/ -obj-$(CONFIG_MMC) += host/ - +obj-$(subst m,y,$(CONFIG_MMC)) += host/ diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1e0e27cbe987..0cad48a284a8 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -107,6 +107,8 @@ struct mmc_blk_data { */ unsigned int part_curr; struct device_attribute force_ro; + struct device_attribute power_ro_lock; + int area_type; }; static DEFINE_MUTEX(open_lock); @@ -119,6 +121,7 @@ enum mmc_blk_status { MMC_BLK_ABORT, MMC_BLK_DATA_ERR, MMC_BLK_ECC_ERR, + MMC_BLK_NOMEDIUM, }; module_param(perdev_minors, int, 0444); @@ -165,6 +168,70 @@ static void mmc_blk_put(struct mmc_blk_data *md) mutex_unlock(&open_lock); } +static ssize_t power_ro_lock_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); + struct mmc_card *card = md->queue.card; + int locked = 0; + + if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN) + locked = 2; + else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) + locked = 1; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); + + return ret; +} + +static ssize_t power_ro_lock_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct mmc_blk_data *md, *part_md; + struct mmc_card *card; + unsigned long set; + + if (kstrtoul(buf, 0, &set)) + return -EINVAL; + + if (set != 1) + return count; + + md = mmc_blk_get(dev_to_disk(dev)); + card = md->queue.card; + + mmc_claim_host(card->host); + + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, + card->ext_csd.boot_ro_lock | + EXT_CSD_BOOT_WP_B_PWR_WP_EN, + card->ext_csd.part_time); + if (ret) + pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); + else + card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; + + mmc_release_host(card->host); + + if (!ret) { + pr_info("%s: Locking boot partition ro until next power on\n", + md->disk->disk_name); + set_disk_ro(md->disk, 1); + + list_for_each_entry(part_md, &md->part, part) + if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) { + pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name); + set_disk_ro(part_md->disk, 1); + } + } + + mmc_blk_put(md); + return count; +} + static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -266,6 +333,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( goto idata_err; } + if (!idata->buf_bytes) + return idata; + idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { err = -ENOMEM; @@ -312,25 +382,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (IS_ERR(idata)) return PTR_ERR(idata); - cmd.opcode = idata->ic.opcode; - cmd.arg = idata->ic.arg; - cmd.flags = idata->ic.flags; - - data.sg = &sg; - data.sg_len = 1; - data.blksz = idata->ic.blksz; - data.blocks = idata->ic.blocks; - - sg_init_one(data.sg, idata->buf, idata->buf_bytes); - - if (idata->ic.write_flag) - data.flags = MMC_DATA_WRITE; - else - data.flags = MMC_DATA_READ; - - mrq.cmd = &cmd; - mrq.data = &data; - md = mmc_blk_get(bdev->bd_disk); if (!md) { err = -EINVAL; @@ -343,6 +394,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_done; } + cmd.opcode = idata->ic.opcode; + cmd.arg = idata->ic.arg; + cmd.flags = idata->ic.flags; + + if (idata->buf_bytes) { + data.sg = &sg; + data.sg_len = 1; + data.blksz = idata->ic.blksz; + data.blocks = idata->ic.blocks; + + sg_init_one(data.sg, idata->buf, idata->buf_bytes); + + if (idata->ic.write_flag) + data.flags = MMC_DATA_WRITE; + else + data.flags = MMC_DATA_READ; + + /* data.flags must already be set before doing this. */ + mmc_set_data_timeout(&data, card); + + /* Allow overriding the timeout_ns for empirical tuning. */ + if (idata->ic.data_timeout_ns) + data.timeout_ns = idata->ic.data_timeout_ns; + + if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { + /* + * Pretend this is a data transfer and rely on the + * host driver to compute timeout. When all host + * drivers support cmd.cmd_timeout for R1B, this + * can be changed to: + * + * mrq.data = NULL; + * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; + */ + data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; + } + + mrq.data = &data; + } + + mrq.cmd = &cmd; + mmc_claim_host(card->host); if (idata->ic.is_acmd) { @@ -351,24 +444,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_rel_host; } - /* data.flags must already be set before doing this. */ - mmc_set_data_timeout(&data, card); - /* Allow overriding the timeout_ns for empirical tuning. */ - if (idata->ic.data_timeout_ns) - data.timeout_ns = idata->ic.data_timeout_ns; - - if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { - /* - * Pretend this is a data transfer and rely on the host driver - * to compute timeout. When all host drivers support - * cmd.cmd_timeout for R1B, this can be changed to: - * - * mrq.data = NULL; - * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; - */ - data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; - } - mmc_wait_for_req(card->host, &mrq); if (cmd.error) { @@ -565,6 +640,7 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries) return err; } +#define ERR_NOMEDIUM 3 #define ERR_RETRY 2 #define ERR_ABORT 1 #define ERR_CONTINUE 0 @@ -632,6 +708,9 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, u32 status, stop_status = 0; int err, retry; + if (mmc_card_removed(card)) + return ERR_NOMEDIUM; + /* * Try to get card status which indicates both the card state * and why there was no response. If the first attempt fails, @@ -648,8 +727,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, } /* We couldn't get a response from the card. Give up. */ - if (err) + if (err) { + /* Check if the card is removed */ + if (mmc_detect_card_removed(card->host)) + return ERR_NOMEDIUM; return ERR_ABORT; + } /* Flag ECC errors */ if ((status & R1_CARD_ECC_FAILED) || @@ -922,6 +1005,8 @@ static int mmc_blk_err_check(struct mmc_card *card, return MMC_BLK_RETRY; case ERR_ABORT: return MMC_BLK_ABORT; + case ERR_NOMEDIUM: + return MMC_BLK_NOMEDIUM; case ERR_CONTINUE: break; } @@ -1255,6 +1340,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) if (!ret) goto start_new_req; break; + case MMC_BLK_NOMEDIUM: + goto cmd_abort; } if (ret) { @@ -1271,6 +1358,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) cmd_abort: spin_lock_irq(&md->lock); + if (mmc_card_removed(card)) + req->cmd_flags |= REQ_QUIET; while (ret) ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); spin_unlock_irq(&md->lock); @@ -1339,7 +1428,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct device *parent, sector_t size, bool default_ro, - const char *subname) + const char *subname, + int area_type) { struct mmc_blk_data *md; int devidx, ret; @@ -1364,11 +1454,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, if (!subname) { md->name_idx = find_first_zero_bit(name_use, max_devices); __set_bit(md->name_idx, name_use); - } - else + } else md->name_idx = ((struct mmc_blk_data *) dev_to_disk(parent)->private_data)->name_idx; + md->area_type = area_type; + /* * Set the read-only status based on the supported commands * and the write protect switch. @@ -1462,7 +1553,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) size = card->csd.capacity << (card->csd.read_blkbits - 9); } - md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL); + md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL, + MMC_BLK_DATA_AREA_MAIN); return md; } @@ -1471,13 +1563,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card, unsigned int part_type, sector_t size, bool default_ro, - const char *subname) + const char *subname, + int area_type) { char cap_str[10]; struct mmc_blk_data *part_md; part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro, - subname); + subname, area_type); if (IS_ERR(part_md)) return PTR_ERR(part_md); part_md->part_type = part_type; @@ -1510,7 +1603,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) card->part[idx].part_cfg, card->part[idx].size >> 9, card->part[idx].force_ro, - card->part[idx].name); + card->part[idx].name, + card->part[idx].area_type); if (ret) return ret; } @@ -1539,9 +1633,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) static void mmc_blk_remove_req(struct mmc_blk_data *md) { + struct mmc_card *card; + if (md) { + card = md->queue.card; if (md->disk->flags & GENHD_FL_UP) { device_remove_file(disk_to_dev(md->disk), &md->force_ro); + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && + card->ext_csd.boot_ro_lockable) + device_remove_file(disk_to_dev(md->disk), + &md->power_ro_lock); /* Stop new requests from getting into the queue */ del_gendisk(md->disk); @@ -1570,6 +1671,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card, static int mmc_add_disk(struct mmc_blk_data *md) { int ret; + struct mmc_card *card = md->queue.card; add_disk(md->disk); md->force_ro.show = force_ro_show; @@ -1579,18 +1681,53 @@ static int mmc_add_disk(struct mmc_blk_data *md) md->force_ro.attr.mode = S_IRUGO | S_IWUSR; ret = device_create_file(disk_to_dev(md->disk), &md->force_ro); if (ret) - del_gendisk(md->disk); + goto force_ro_fail; + + if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && + card->ext_csd.boot_ro_lockable) { + mode_t mode; + + if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) + mode = S_IRUGO; + else + mode = S_IRUGO | S_IWUSR; + + md->power_ro_lock.show = power_ro_lock_show; + md->power_ro_lock.store = power_ro_lock_store; + md->power_ro_lock.attr.mode = mode; + md->power_ro_lock.attr.name = + "ro_lock_until_next_power_on"; + ret = device_create_file(disk_to_dev(md->disk), + &md->power_ro_lock); + if (ret) + goto power_ro_lock_fail; + } + return ret; + +power_ro_lock_fail: + device_remove_file(disk_to_dev(md->disk), &md->force_ro); +force_ro_fail: + del_gendisk(md->disk); return ret; } +#define CID_MANFID_SANDISK 0x2 +#define CID_MANFID_TOSHIBA 0x11 +#define CID_MANFID_MICRON 0x13 + static const struct mmc_fixup blk_fixups[] = { - MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), - MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), + MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk, + MMC_QUIRK_INAND_CMD38), /* * Some MMC cards experience performance degradation with CMD23 @@ -1600,18 +1737,18 @@ static const struct mmc_fixup blk_fixups[] = * * N.B. This doesn't affect SD cards. */ - MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), - MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc, + MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), /* * Some Micron MMC cards needs longer data read timeout than * indicated in CSD. */ - MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc, + MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, MMC_QUIRK_LONG_READ_TIME), END_FIXUP diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index e99bdc18002d..759714ed6bee 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -1581,6 +1581,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) t->max_segs = test->card->host->max_segs; t->max_seg_sz = test->card->host->max_seg_size; + t->max_seg_sz -= t->max_seg_sz % 512; t->max_tfr = t->max_sz; if (t->max_tfr >> 9 > test->card->host->max_blk_count) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index dcad59cbfef1..2517547b4366 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -29,6 +29,8 @@ */ static int mmc_prep_request(struct request_queue *q, struct request *req) { + struct mmc_queue *mq = q->queuedata; + /* * We only like normal block requests and discards. */ @@ -37,6 +39,9 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) return BLKPREP_KILL; } + if (mq && mmc_card_removed(mq->card)) + return BLKPREP_KILL; + req->cmd_flags |= REQ_DONTPREP; return BLKPREP_OK; diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 639501970b41..dca4428380f1 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,6 +7,6 @@ mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ - quirks.o + quirks.o cd-gpio.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 6be49249895a..5d011a39dfff 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -303,10 +303,11 @@ int mmc_add_card(struct mmc_card *card) mmc_card_ddr_mode(card) ? "DDR " : "", type); } else { - printk(KERN_INFO "%s: new %s%s%s card at address %04x\n", + pr_info("%s: new %s%s%s%s card at address %04x\n", mmc_hostname(card->host), - mmc_sd_card_uhs(card) ? "ultra high speed " : + mmc_card_uhs(card) ? "ultra high speed " : (mmc_card_highspeed(card) ? "high speed " : ""), + (mmc_card_hs200(card) ? "HS200 " : ""), mmc_card_ddr_mode(card) ? "DDR " : "", type, card->rca); } diff --git a/drivers/mmc/core/cd-gpio.c b/drivers/mmc/core/cd-gpio.c new file mode 100644 index 000000000000..082202ae4a03 --- /dev/null +++ b/drivers/mmc/core/cd-gpio.c @@ -0,0 +1,74 @@ +/* + * Generic GPIO card-detect helper + * + * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * 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 <linux/err.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/mmc/host.h> +#include <linux/module.h> +#include <linux/slab.h> + +struct mmc_cd_gpio { + unsigned int gpio; + char label[0]; +}; + +static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id) +{ + /* Schedule a card detection after a debounce timeout */ + mmc_detect_change(dev_id, msecs_to_jiffies(100)); + return IRQ_HANDLED; +} + +int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio, + unsigned int irq, unsigned long flags) +{ + size_t len = strlen(dev_name(host->parent)) + 4; + struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL); + int ret; + + if (!cd) + return -ENOMEM; + + snprintf(cd->label, len, "%s cd", dev_name(host->parent)); + + ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label); + if (ret < 0) + goto egpioreq; + + ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt, + flags, cd->label, host); + if (ret < 0) + goto eirqreq; + + cd->gpio = gpio; + host->hotplug.irq = irq; + host->hotplug.handler_priv = cd; + + return 0; + +eirqreq: + gpio_free(gpio); +egpioreq: + kfree(cd); + return ret; +} +EXPORT_SYMBOL(mmc_cd_gpio_request); + +void mmc_cd_gpio_free(struct mmc_host *host) +{ + struct mmc_cd_gpio *cd = host->hotplug.handler_priv; + + free_irq(host->hotplug.irq, host); + gpio_free(cd->gpio); + kfree(cd); +} +EXPORT_SYMBOL(mmc_cd_gpio_free); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 950b97d7412a..f545a3e6eb80 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -48,7 +48,7 @@ static struct workqueue_struct *workqueue; * performance cost, and for other reasons may not always be desired. * So we allow it it to be disabled. */ -int use_spi_crc = 1; +bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); /* @@ -58,9 +58,9 @@ module_param(use_spi_crc, bool, 0); * overridden if necessary. */ #ifdef CONFIG_MMC_UNSAFE_RESUME -int mmc_assume_removable; +bool mmc_assume_removable; #else -int mmc_assume_removable = 1; +bool mmc_assume_removable = 1; #endif EXPORT_SYMBOL(mmc_assume_removable); module_param_named(removable, mmc_assume_removable, bool, 0644); @@ -140,7 +140,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->retries = 0; } - if (err && cmd->retries) { + if (err && cmd->retries && !mmc_card_removed(host->card)) { /* * Request starter must handle retries - see * mmc_wait_for_req_done(). @@ -247,6 +247,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) { init_completion(&mrq->completion); mrq->done = mmc_wait_done; + if (mmc_card_removed(host->card)) { + mrq->cmd->error = -ENOMEDIUM; + complete(&mrq->completion); + return; + } mmc_start_request(host, mrq); } @@ -259,7 +264,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host, wait_for_completion(&mrq->completion); cmd = mrq->cmd; - if (!cmd->error || !cmd->retries) + if (!cmd->error || !cmd->retries || + mmc_card_removed(host->card)) break; pr_debug("%s: req failed (CMD%u): %d, retrying...\n", @@ -1456,7 +1462,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay) WARN_ON(host->removed); spin_unlock_irqrestore(&host->lock, flags); #endif - + host->detect_change = 1; mmc_schedule_delayed_work(&host->detect, delay); } @@ -2049,6 +2055,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) return -EIO; } +int _mmc_detect_card_removed(struct mmc_host *host) +{ + int ret; + + if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) + return 0; + + if (!host->card || mmc_card_removed(host->card)) + return 1; + + ret = host->bus_ops->alive(host); + if (ret) { + mmc_card_set_removed(host->card); + pr_debug("%s: card remove detected\n", mmc_hostname(host)); + } + + return ret; +} + +int mmc_detect_card_removed(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + + WARN_ON(!host->claimed); + /* + * The card will be considered unchanged unless we have been asked to + * detect a change or host requires polling to provide card detection. + */ + if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL)) + return mmc_card_removed(card); + + host->detect_change = 0; + + return _mmc_detect_card_removed(host); +} +EXPORT_SYMBOL(mmc_detect_card_removed); + void mmc_rescan(struct work_struct *work) { static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; @@ -2069,6 +2112,8 @@ void mmc_rescan(struct work_struct *work) && !(host->caps & MMC_CAP_NONREMOVABLE)) host->bus_ops->detect(host); + host->detect_change = 0; + /* * Let mmc_bus_put() free the bus/bus_ops if we've found that * the card is no longer present. @@ -2130,6 +2175,7 @@ void mmc_stop_host(struct mmc_host *host) mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { + /* Calling bus_ops->remove() with a claimed host can deadlock */ if (host->bus_ops->remove) host->bus_ops->remove(host); @@ -2201,6 +2247,9 @@ int mmc_card_awake(struct mmc_host *host) { int err = -ENOSYS; + if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) + return 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) @@ -2216,6 +2265,9 @@ int mmc_card_sleep(struct mmc_host *host) { int err = -ENOSYS; + if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) + return 0; + mmc_bus_get(host); if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep) @@ -2270,6 +2322,7 @@ EXPORT_SYMBOL(mmc_flush_cache); int mmc_cache_ctrl(struct mmc_host *host, u8 enable) { struct mmc_card *card = host->card; + unsigned int timeout; int err = 0; if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || @@ -2280,16 +2333,18 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable) (card->ext_csd.cache_size > 0)) { enable = !!enable; - if (card->ext_csd.cache_ctrl ^ enable) + if (card->ext_csd.cache_ctrl ^ enable) { + timeout = enable ? card->ext_csd.generic_cmd6_time : 0; err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, enable, 0); - if (err) - pr_err("%s: cache %s error %d\n", - mmc_hostname(card->host), - enable ? "on" : "off", - err); - else - card->ext_csd.cache_ctrl = enable; + EXT_CSD_CACHE_CTRL, enable, timeout); + if (err) + pr_err("%s: cache %s error %d\n", + mmc_hostname(card->host), + enable ? "on" : "off", + err); + else + card->ext_csd.cache_ctrl = enable; + } } return err; @@ -2310,7 +2365,13 @@ int mmc_suspend_host(struct mmc_host *host) cancel_delayed_work(&host->disable); cancel_delayed_work(&host->detect); mmc_flush_scheduled_work(); - err = mmc_cache_ctrl(host, 0); + if (mmc_try_claim_host(host)) { + err = mmc_cache_ctrl(host, 0); + mmc_do_release_host(host); + } else { + err = -EBUSY; + } + if (err) goto out; @@ -2338,7 +2399,9 @@ int mmc_suspend_host(struct mmc_host *host) if (err == -ENOSYS || !host->bus_ops->resume) { /* * We simply "remove" the card in this case. - * It will be redetected on resume. + * It will be redetected on resume. (Calling + * bus_ops->remove() with a claimed host can + * deadlock.) */ if (host->bus_ops->remove) host->bus_ops->remove(host); @@ -2431,11 +2494,11 @@ int mmc_pm_notify(struct notifier_block *notify_block, if (!host->bus_ops || host->bus_ops->suspend) break; - mmc_claim_host(host); - + /* Calling bus_ops->remove() with a claimed host can deadlock */ if (host->bus_ops->remove) host->bus_ops->remove(host); + mmc_claim_host(host); mmc_detach_bus(host); mmc_power_off(host); mmc_release_host(host); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 14664f1fb16f..3bdafbca354f 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -24,6 +24,7 @@ struct mmc_bus_ops { int (*resume)(struct mmc_host *); int (*power_save)(struct mmc_host *); int (*power_restore)(struct mmc_host *); + int (*alive)(struct mmc_host *); }; void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops); @@ -59,12 +60,14 @@ void mmc_rescan(struct work_struct *work); void mmc_start_host(struct mmc_host *host); void mmc_stop_host(struct mmc_host *host); +int _mmc_detect_card_removed(struct mmc_host *host); + int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); /* Module parameters */ -extern int use_spi_crc; +extern bool use_spi_crc; /* Debugfs information for hosts and cards */ void mmc_add_host_debugfs(struct mmc_host *host); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 3923880118b6..9ab5b17d488a 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -57,6 +57,8 @@ static int mmc_ios_show(struct seq_file *s, void *data) const char *str; seq_printf(s, "clock:\t\t%u Hz\n", ios->clock); + if (host->actual_clock) + seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock); seq_printf(s, "vdd:\t\t%u ", ios->vdd); if ((1 << ios->vdd) & MMC_VDD_165_195) seq_printf(s, "(1.65 - 1.95 V)\n"); @@ -133,6 +135,9 @@ static int mmc_ios_show(struct seq_file *s, void *data) case MMC_TIMING_UHS_DDR50: str = "sd uhs DDR50"; break; + case MMC_TIMING_MMC_HS200: + str = "mmc high-speed SDR200"; + break; default: str = "invalid"; break; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index d31c78b72b0f..30055f2b0d44 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -54,6 +54,27 @@ static DEFINE_IDR(mmc_host_idr); static DEFINE_SPINLOCK(mmc_host_lock); #ifdef CONFIG_MMC_CLKGATE +static ssize_t clkgate_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay); +} + +static ssize_t clkgate_delay_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + unsigned long flags, value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + spin_lock_irqsave(&host->clk_lock, flags); + host->clkgate_delay = value; + spin_unlock_irqrestore(&host->clk_lock, flags); + return count; +} /* * Enabling clock gating will make the core call out to the host @@ -114,7 +135,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) static void mmc_host_clk_gate_work(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, - clk_gate_work); + clk_gate_work.work); mmc_host_clk_gate_delayed(host); } @@ -131,6 +152,8 @@ void mmc_host_clk_hold(struct mmc_host *host) { unsigned long flags; + /* cancel any clock gating work scheduled by mmc_host_clk_release() */ + cancel_delayed_work_sync(&host->clk_gate_work); mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { @@ -180,7 +203,8 @@ void mmc_host_clk_release(struct mmc_host *host) host->clk_requests--; if (mmc_host_may_gate_card(host->card) && !host->clk_requests) - queue_work(system_nrt_wq, &host->clk_gate_work); + queue_delayed_work(system_nrt_wq, &host->clk_gate_work, + msecs_to_jiffies(host->clkgate_delay)); spin_unlock_irqrestore(&host->clk_lock, flags); } @@ -213,8 +237,13 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_requests = 0; /* Hold MCI clock for 8 cycles by default */ host->clk_delay = 8; + /* + * Default clock gating delay is 200ms. + * This value can be tuned by writing into sysfs entry. + */ + host->clkgate_delay = 200; host->clk_gated = false; - INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); + INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); mutex_init(&host->clk_gate_mutex); } @@ -229,7 +258,7 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) * Wait for any outstanding gate and then make sure we're * ungated before exiting. */ - if (cancel_work_sync(&host->clk_gate_work)) + if (cancel_delayed_work_sync(&host->clk_gate_work)) mmc_host_clk_gate_delayed(host); if (host->clk_gated) mmc_host_clk_hold(host); @@ -237,6 +266,17 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) WARN_ON(host->clk_requests > 1); } +static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) +{ + host->clkgate_delay_attr.show = clkgate_delay_show; + host->clkgate_delay_attr.store = clkgate_delay_store; + sysfs_attr_init(&host->clkgate_delay_attr.attr); + host->clkgate_delay_attr.attr.name = "clkgate_delay"; + host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR; + if (device_create_file(&host->class_dev, &host->clkgate_delay_attr)) + pr_err("%s: Failed to create clkgate_delay sysfs entry\n", + mmc_hostname(host)); +} #else static inline void mmc_host_clk_init(struct mmc_host *host) @@ -247,6 +287,10 @@ static inline void mmc_host_clk_exit(struct mmc_host *host) { } +static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) +{ +} + #endif /** @@ -335,6 +379,7 @@ int mmc_add_host(struct mmc_host *host) #ifdef CONFIG_DEBUG_FS mmc_add_host_debugfs(host); #endif + mmc_host_clk_sysfs_init(host); mmc_start_host(host); register_pm_notifier(&host->pm_notify); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index d240427c1246..59b9ba52e66a 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -286,6 +286,27 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) } card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) { + case EXT_CSD_CARD_TYPE_SDR_ALL: + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V: + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V: + case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52: + card->ext_csd.hs_max_dtr = 200000000; + card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200; + break; + case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL: + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V: + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V: + case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52: + card->ext_csd.hs_max_dtr = 200000000; + card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V; + break; + case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL: + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V: + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V: + case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52: + card->ext_csd.hs_max_dtr = 200000000; + card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V; + break; case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26: card->ext_csd.hs_max_dtr = 52000000; @@ -348,7 +369,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; mmc_part_add(card, part_size, EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, - "boot%d", idx, true); + "boot%d", idx, true, + MMC_BLK_DATA_AREA_BOOT); } } } @@ -435,7 +457,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) hc_wp_grp_sz); mmc_part_add(card, part_size << 19, EXT_CSD_PART_CONFIG_ACC_GP0 + idx, - "gp%d", idx, false); + "gp%d", idx, false, + MMC_BLK_DATA_AREA_GP); } } card->ext_csd.sec_trim_mult = @@ -446,6 +469,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.trim_timeout = 300 * ext_csd[EXT_CSD_TRIM_MULT]; + + /* + * Note that the call to mmc_part_add above defaults to read + * only. If this default assumption is changed, the call must + * take into account the value of boot_locked below. + */ + card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP]; + card->ext_csd.boot_ro_lockable = true; } if (card->ext_csd.rev >= 5) { @@ -690,6 +721,79 @@ static int mmc_select_powerclass(struct mmc_card *card, } /* + * Selects the desired buswidth and switch to the HS200 mode + * if bus width set without error + */ +static int mmc_select_hs200(struct mmc_card *card) +{ + int idx, err = 0; + struct mmc_host *host; + static unsigned ext_csd_bits[] = { + EXT_CSD_BUS_WIDTH_4, + EXT_CSD_BUS_WIDTH_8, + }; + static unsigned bus_widths[] = { + MMC_BUS_WIDTH_4, + MMC_BUS_WIDTH_8, + }; + + BUG_ON(!card); + + host = card->host; + + if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V && + host->caps2 & MMC_CAP2_HS200_1_2V_SDR) + if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0)) + err = mmc_set_signal_voltage(host, + MMC_SIGNAL_VOLTAGE_180, 0); + + /* If fails try again during next card power cycle */ + if (err) + goto err; + + idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0; + + /* + * Unlike SD, MMC cards dont have a configuration register to notify + * supported bus width. So bus test command should be run to identify + * the supported bus width or compare the ext csd values of current + * bus width and ext csd values of 1 bit mode read earlier. + */ + for (; idx >= 0; idx--) { + + /* + * Host is capable of 8bit transfer, then switch + * the device to work in 8bit transfer mode. If the + * mmc switch command returns error then switch to + * 4bit transfer mode. On success set the corresponding + * bus width on the host. + */ + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_BUS_WIDTH, + ext_csd_bits[idx], + card->ext_csd.generic_cmd6_time); + if (err) + continue; + + mmc_set_bus_width(card->host, bus_widths[idx]); + + if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) + err = mmc_compare_ext_csds(card, bus_widths[idx]); + else + err = mmc_bus_test(card, bus_widths[idx]); + if (!err) + break; + } + + /* switch to HS200 mode if bus width set successfully */ + if (!err) + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 2, 0); +err: + return err; +} + +/* * Handle the detection and initialisation of a card. * * In the case of a resume, "oldcard" will contain the card @@ -895,11 +999,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * Activate high speed (if supported) */ - if ((card->ext_csd.hs_max_dtr != 0) && - (host->caps & MMC_CAP_MMC_HIGHSPEED)) { - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, 1, - card->ext_csd.generic_cmd6_time); + if (card->ext_csd.hs_max_dtr != 0) { + err = 0; + if (card->ext_csd.hs_max_dtr > 52000000 && + host->caps2 & MMC_CAP2_HS200) + err = mmc_select_hs200(card); + else if (host->caps & MMC_CAP_MMC_HIGHSPEED) + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, 1, 0); + if (err && err != -EBADMSG) goto free_card; @@ -908,8 +1016,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_hostname(card->host)); err = 0; } else { - mmc_card_set_highspeed(card); - mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + if (card->ext_csd.hs_max_dtr > 52000000 && + host->caps2 & MMC_CAP2_HS200) { + mmc_card_set_hs200(card); + mmc_set_timing(card->host, + MMC_TIMING_MMC_HS200); + } else { + mmc_card_set_highspeed(card); + mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + } } } @@ -934,7 +1049,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, */ max_dtr = (unsigned int)-1; - if (mmc_card_highspeed(card)) { + if (mmc_card_highspeed(card) || mmc_card_hs200(card)) { if (max_dtr > card->ext_csd.hs_max_dtr) max_dtr = card->ext_csd.hs_max_dtr; } else if (max_dtr > card->csd.max_dtr) { @@ -960,9 +1075,48 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, } /* + * Indicate HS200 SDR mode (if supported). + */ + if (mmc_card_hs200(card)) { + u32 ext_csd_bits; + u32 bus_width = card->host->ios.bus_width; + + /* + * For devices supporting HS200 mode, the bus width has + * to be set before executing the tuning function. If + * set before tuning, then device will respond with CRC + * errors for responses on CMD line. So for HS200 the + * sequence will be + * 1. set bus width 4bit / 8 bit (1 bit not supported) + * 2. switch to HS200 mode + * 3. set the clock to > 52Mhz <=200MHz and + * 4. execute tuning for HS200 + */ + if ((host->caps2 & MMC_CAP2_HS200) && + card->host->ops->execute_tuning) + err = card->host->ops->execute_tuning(card->host, + MMC_SEND_TUNING_BLOCK_HS200); + if (err) { + pr_warning("%s: tuning execution failed\n", + mmc_hostname(card->host)); + goto err; + } + + ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ? + EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4; + err = mmc_select_powerclass(card, ext_csd_bits, ext_csd); + if (err) { + pr_err("%s: power class selection to bus width %d failed\n", + mmc_hostname(card->host), 1 << bus_width); + goto err; + } + } + + /* * Activate wide bus and DDR (if supported). */ - if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && + if (!mmc_card_hs200(card) && + (card->csd.mmca_vsn >= CSD_SPEC_VER_3) && (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) { static unsigned ext_csd_bits[][2] = { { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 }, @@ -1048,7 +1202,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * * WARNING: eMMC rules are NOT the same as SD DDR */ - if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) { + if (ddr == MMC_1_2V_DDR_MODE) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0); if (err) @@ -1067,14 +1221,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && card->ext_csd.cache_size > 0) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_CACHE_CTRL, 1, 0); + EXT_CSD_CACHE_CTRL, 1, + card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) goto free_card; /* * Only if no error, cache is turned on successfully. */ - card->ext_csd.cache_ctrl = err ? 0 : 1; + if (err) { + pr_warning("%s: Cache is supported, " + "but failed to turn on (%d)\n", + mmc_hostname(card->host), err); + card->ext_csd.cache_ctrl = 0; + err = 0; + } else { + card->ext_csd.cache_ctrl = 1; + } } if (!oldcard) @@ -1105,6 +1268,14 @@ static void mmc_remove(struct mmc_host *host) } /* + * Card detection - card is alive. + */ +static int mmc_alive(struct mmc_host *host) +{ + return mmc_send_status(host->card, NULL); +} + +/* * Card detection callback from host. */ static void mmc_detect(struct mmc_host *host) @@ -1119,7 +1290,7 @@ static void mmc_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = mmc_send_status(host->card, NULL); + err = _mmc_detect_card_removed(host); mmc_release_host(host); @@ -1224,6 +1395,7 @@ static const struct mmc_bus_ops mmc_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_power_restore, + .alive = mmc_alive, }; static const struct mmc_bus_ops mmc_ops_unsafe = { @@ -1234,6 +1406,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = { .suspend = mmc_suspend, .resume = mmc_resume, .power_restore = mmc_power_restore, + .alive = mmc_alive, }; static void mmc_attach_bus_ops(struct mmc_host *host) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index f2a05ea40f2a..c63ad03c29c7 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -307,8 +307,8 @@ static int mmc_read_switch(struct mmc_card *card) goto out; } - if (status[13] & UHS_SDR50_BUS_SPEED) - card->sw_caps.hs_max_dtr = 50000000; + if (status[13] & SD_MODE_HIGH_SPEED) + card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR; if (card->scr.sda_spec3) { card->sw_caps.sd3_bus_mode = status[13]; @@ -661,7 +661,8 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) /* SPI mode doesn't define CMD19 */ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) - err = card->host->ops->execute_tuning(card->host); + err = card->host->ops->execute_tuning(card->host, + MMC_SEND_TUNING_BLOCK); out: kfree(status); @@ -960,7 +961,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; /* Card is an ultra-high-speed card */ - mmc_sd_card_set_uhs(card); + mmc_card_set_uhs(card); /* * Since initialization is now complete, enable preset @@ -1019,6 +1020,14 @@ static void mmc_sd_remove(struct mmc_host *host) } /* + * Card detection - card is alive. + */ +static int mmc_sd_alive(struct mmc_host *host) +{ + return mmc_send_status(host->card, NULL); +} + +/* * Card detection callback from host. */ static void mmc_sd_detect(struct mmc_host *host) @@ -1033,7 +1042,7 @@ static void mmc_sd_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = mmc_send_status(host->card, NULL); + err = _mmc_detect_card_removed(host); mmc_release_host(host); @@ -1102,6 +1111,7 @@ static const struct mmc_bus_ops mmc_sd_ops = { .suspend = NULL, .resume = NULL, .power_restore = mmc_sd_power_restore, + .alive = mmc_sd_alive, }; static const struct mmc_bus_ops mmc_sd_ops_unsafe = { @@ -1110,6 +1120,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = { .suspend = mmc_sd_suspend, .resume = mmc_sd_resume, .power_restore = mmc_sd_power_restore, + .alive = mmc_sd_alive, }; static void mmc_sd_attach_bus_ops(struct mmc_host *host) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 3ab565e32a6a..bd7bacc950dc 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -14,6 +14,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/mmc.h> #include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> @@ -102,6 +103,7 @@ static int sdio_read_cccr(struct mmc_card *card) int ret; int cccr_vsn; unsigned char data; + unsigned char speed; memset(&card->cccr, 0, sizeof(struct sdio_cccr)); @@ -140,12 +142,60 @@ static int sdio_read_cccr(struct mmc_card *card) } if (cccr_vsn >= SDIO_CCCR_REV_1_20) { - ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); if (ret) goto out; - if (data & SDIO_SPEED_SHS) - card->cccr.high_speed = 1; + card->scr.sda_spec3 = 0; + card->sw_caps.sd3_bus_mode = 0; + card->sw_caps.sd3_drv_type = 0; + if (cccr_vsn >= SDIO_CCCR_REV_3_00) { + card->scr.sda_spec3 = 1; + ret = mmc_io_rw_direct(card, 0, 0, + SDIO_CCCR_UHS, 0, &data); + if (ret) + goto out; + + if (card->host->caps & + (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50)) { + if (data & SDIO_UHS_DDR50) + card->sw_caps.sd3_bus_mode + |= SD_MODE_UHS_DDR50; + + if (data & SDIO_UHS_SDR50) + card->sw_caps.sd3_bus_mode + |= SD_MODE_UHS_SDR50; + + if (data & SDIO_UHS_SDR104) + card->sw_caps.sd3_bus_mode + |= SD_MODE_UHS_SDR104; + } + + ret = mmc_io_rw_direct(card, 0, 0, + SDIO_CCCR_DRIVE_STRENGTH, 0, &data); + if (ret) + goto out; + + if (data & SDIO_DRIVE_SDTA) + card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A; + if (data & SDIO_DRIVE_SDTC) + card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C; + if (data & SDIO_DRIVE_SDTD) + card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D; + } + + /* if no uhs mode ensure we check for high speed */ + if (!card->sw_caps.sd3_bus_mode) { + if (speed & SDIO_SPEED_SHS) { + card->cccr.high_speed = 1; + card->sw_caps.hs_max_dtr = 50000000; + } else { + card->cccr.high_speed = 0; + card->sw_caps.hs_max_dtr = 25000000; + } + } } out: @@ -327,6 +377,194 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) return max_dtr; } +static unsigned char host_drive_to_sdio_drive(int host_strength) +{ + switch (host_strength) { + case MMC_SET_DRIVER_TYPE_A: + return SDIO_DTSx_SET_TYPE_A; + case MMC_SET_DRIVER_TYPE_B: + return SDIO_DTSx_SET_TYPE_B; + case MMC_SET_DRIVER_TYPE_C: + return SDIO_DTSx_SET_TYPE_C; + case MMC_SET_DRIVER_TYPE_D: + return SDIO_DTSx_SET_TYPE_D; + default: + return SDIO_DTSx_SET_TYPE_B; + } +} + +static void sdio_select_driver_type(struct mmc_card *card) +{ + int host_drv_type = SD_DRIVER_TYPE_B; + int card_drv_type = SD_DRIVER_TYPE_B; + int drive_strength; + unsigned char card_strength; + int err; + + /* + * If the host doesn't support any of the Driver Types A,C or D, + * or there is no board specific handler then default Driver + * Type B is used. + */ + if (!(card->host->caps & + (MMC_CAP_DRIVER_TYPE_A | + MMC_CAP_DRIVER_TYPE_C | + MMC_CAP_DRIVER_TYPE_D))) + return; + + if (!card->host->ops->select_drive_strength) + return; + + if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) + host_drv_type |= SD_DRIVER_TYPE_A; + + if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) + host_drv_type |= SD_DRIVER_TYPE_C; + + if (card->host->caps & MMC_CAP_DRIVER_TYPE_D) + host_drv_type |= SD_DRIVER_TYPE_D; + + if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A) + card_drv_type |= SD_DRIVER_TYPE_A; + + if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) + card_drv_type |= SD_DRIVER_TYPE_C; + + if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D) + card_drv_type |= SD_DRIVER_TYPE_D; + + /* + * The drive strength that the hardware can support + * depends on the board design. Pass the appropriate + * information and let the hardware specific code + * return what is possible given the options + */ + drive_strength = card->host->ops->select_drive_strength( + card->sw_caps.uhs_max_dtr, + host_drv_type, card_drv_type); + + /* if error just use default for drive strength B */ + err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, + &card_strength); + if (err) + return; + + card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); + card_strength |= host_drive_to_sdio_drive(drive_strength); + + err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, + card_strength, NULL); + + /* if error default to drive strength B */ + if (!err) + mmc_set_driver_type(card->host, drive_strength); +} + + +static int sdio_set_bus_speed_mode(struct mmc_card *card) +{ + unsigned int bus_speed, timing; + int err; + unsigned char speed; + + /* + * If the host doesn't support any of the UHS-I modes, fallback on + * default speed. + */ + if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) + return 0; + + bus_speed = SDIO_SPEED_SDR12; + timing = MMC_TIMING_UHS_SDR12; + if ((card->host->caps & MMC_CAP_UHS_SDR104) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { + bus_speed = SDIO_SPEED_SDR104; + timing = MMC_TIMING_UHS_SDR104; + card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; + } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { + bus_speed = SDIO_SPEED_DDR50; + timing = MMC_TIMING_UHS_DDR50; + card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; + } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & + SD_MODE_UHS_SDR50)) { + bus_speed = SDIO_SPEED_SDR50; + timing = MMC_TIMING_UHS_SDR50; + card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; + } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { + bus_speed = SDIO_SPEED_SDR25; + timing = MMC_TIMING_UHS_SDR25; + card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; + } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & + SD_MODE_UHS_SDR12)) { + bus_speed = SDIO_SPEED_SDR12; + timing = MMC_TIMING_UHS_SDR12; + card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; + } + + err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); + if (err) + return err; + + speed &= ~SDIO_SPEED_BSS_MASK; + speed |= bus_speed; + err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); + if (err) + return err; + + if (bus_speed) { + mmc_set_timing(card->host, timing); + mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); + } + + return 0; +} + +/* + * UHS-I specific initialization procedure + */ +static int mmc_sdio_init_uhs_card(struct mmc_card *card) +{ + int err; + + if (!card->scr.sda_spec3) + return 0; + + /* + * Switch to wider bus (if supported). + */ + if (card->host->caps & MMC_CAP_4_BIT_DATA) { + err = sdio_enable_4bit_bus(card); + if (err > 0) { + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + err = 0; + } + } + + /* Set the driver strength for the card */ + sdio_select_driver_type(card); + + /* Set bus speed mode of the card */ + err = sdio_set_bus_speed_mode(card); + if (err) + goto out; + + /* Initialize and start re-tuning timer */ + if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) + err = card->host->ops->execute_tuning(card->host, + MMC_SEND_TUNING_BLOCK); + +out: + + return err; +} + /* * Handle the detection and initialisation of a card. * @@ -394,6 +632,30 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, host->ops->init_card(host, card); /* + * If the host and card support UHS-I mode request the card + * to switch to 1.8V signaling level. No 1.8v signalling if + * UHS mode is not enabled to maintain compatibilty and some + * systems that claim 1.8v signalling in fact do not support + * it. + */ + if ((ocr & R4_18V_PRESENT) && + (host->caps & + (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | + MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | + MMC_CAP_UHS_DDR50))) { + err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, + true); + if (err) { + ocr &= ~R4_18V_PRESENT; + host->ocr &= ~R4_18V_PRESENT; + } + err = 0; + } else { + ocr &= ~R4_18V_PRESENT; + host->ocr &= ~R4_18V_PRESENT; + } + + /* * For native busses: set card RCA and quit open drain mode. */ if (!powered_resume && !mmc_host_is_spi(host)) { @@ -492,29 +754,39 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (err) goto remove; - /* - * Switch to high-speed (if supported). - */ - err = sdio_enable_hs(card); - if (err > 0) - mmc_sd_go_highspeed(card); - else if (err) - goto remove; + /* Initialization sequence for UHS-I cards */ + /* Only if card supports 1.8v and UHS signaling */ + if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) { + err = mmc_sdio_init_uhs_card(card); + if (err) + goto remove; - /* - * Change to the card's maximum speed. - */ - mmc_set_clock(host, mmc_sdio_get_max_clock(card)); + /* Card is an ultra-high-speed card */ + mmc_card_set_uhs(card); + } else { + /* + * Switch to high-speed (if supported). + */ + err = sdio_enable_hs(card); + if (err > 0) + mmc_sd_go_highspeed(card); + else if (err) + goto remove; - /* - * Switch to wider bus (if supported). - */ - err = sdio_enable_4bit_bus(card); - if (err > 0) - mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); - else if (err) - goto remove; + /* + * Change to the card's maximum speed. + */ + mmc_set_clock(host, mmc_sdio_get_max_clock(card)); + /* + * Switch to wider bus (if supported). + */ + err = sdio_enable_4bit_bus(card); + if (err > 0) + mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); + else if (err) + goto remove; + } finish: if (!oldcard) host->card = card; @@ -550,6 +822,14 @@ static void mmc_sdio_remove(struct mmc_host *host) } /* + * Card detection - card is alive. + */ +static int mmc_sdio_alive(struct mmc_host *host) +{ + return mmc_select_card(host->card); +} + +/* * Card detection callback from host. */ static void mmc_sdio_detect(struct mmc_host *host) @@ -571,7 +851,7 @@ static void mmc_sdio_detect(struct mmc_host *host) /* * Just check if our card has been removed. */ - err = mmc_select_card(host->card); + err = _mmc_detect_card_removed(host); mmc_release_host(host); @@ -749,6 +1029,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .suspend = mmc_sdio_suspend, .resume = mmc_sdio_resume, .power_restore = mmc_sdio_power_restore, + .alive = mmc_sdio_alive, }; @@ -797,8 +1078,17 @@ int mmc_attach_sdio(struct mmc_host *host) * Detect and init the card. */ err = mmc_sdio_init_card(host, host->ocr, NULL, 0); - if (err) - goto err; + if (err) { + if (err == -EAGAIN) { + /* + * Retry initialization with S18R set to 0. + */ + host->ocr &= ~R4_18V_PRESENT; + err = mmc_sdio_init_card(host, host->ocr, NULL, 0); + } + if (err) + goto err; + } card = host->card; /* diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index b1f3168f791b..8f6f5ac131fc 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -196,6 +196,9 @@ static inline unsigned int sdio_max_byte_size(struct sdio_func *func) else mval = min(mval, func->max_blksize); + if (mmc_card_broken_byte_mode_512(func->card)) + return min(mval, 511u); + return min(mval, 512u); /* maximum size for byte mode */ } @@ -314,7 +317,7 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, func->card->host->max_seg_size / func->cur_blksize); max_blocks = min(max_blocks, 511u); - while (remainder > func->cur_blksize) { + while (remainder >= func->cur_blksize) { unsigned blocks; blocks = remainder / func->cur_blksize; @@ -339,8 +342,9 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, while (remainder > 0) { size = min(remainder, sdio_max_byte_size(func)); + /* Indicate byte mode by setting "blocks" = 0 */ ret = mmc_io_rw_extended(func->card, write, func->num, addr, - incr_addr, buf, 1, size); + incr_addr, buf, 0, size); if (ret) return ret; diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index b0517cc06200..d29e20630eed 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -128,8 +128,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, BUG_ON(!card); BUG_ON(fn > 7); - BUG_ON(blocks == 1 && blksz > 512); - WARN_ON(blocks == 0); WARN_ON(blksz == 0); /* sanity check */ @@ -144,22 +142,20 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, cmd.arg |= fn << 28; cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; cmd.arg |= addr << 9; - if (blocks == 1 && blksz < 512) - cmd.arg |= blksz; /* byte mode */ - else if (blocks == 1 && blksz == 512 && - !(mmc_card_broken_byte_mode_512(card))) - cmd.arg |= 0; /* byte mode, 0==512 */ + if (blocks == 0) + cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */ else cmd.arg |= 0x08000000 | blocks; /* block mode */ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; data.blksz = blksz; - data.blocks = blocks; + /* Code in host drivers/fwk assumes that "blocks" always is >=1 */ + data.blocks = blocks ? blocks : 1; data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, buf, blksz * blocks); + sg_init_one(&sg, buf, data.blksz * data.blocks); mmc_set_data_timeout(&data, card); diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index b4b83f302e32..745f8fce2519 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o +obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index f437c3e6f3aa..947faa5d2ce4 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -236,7 +236,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data sg = &data->sg[i]; - sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; amount = min(size, sg->length); size -= amount; @@ -252,7 +252,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data dmabuf = (unsigned *)tmpv; } - kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); + kunmap_atomic(sgbuffer); if (size == 0) break; @@ -302,7 +302,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) sg = &data->sg[i]; - sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; amount = min(size, sg->length); size -= amount; @@ -318,7 +318,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host) } flush_kernel_dcache_page(sg_page(sg)); - kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); + kunmap_atomic(sgbuffer); data->bytes_xfered += amount; if (size == 0) break; diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 5d3b9ae64523..dbd0c8a4e98a 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -153,6 +153,7 @@ static inline int has_dbdma(void) { switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1200: + case ALCHEMY_CPU_AU1300: return 1; default: return 0; @@ -768,11 +769,15 @@ static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) config2 = au_readl(HOST_CONFIG2(host)); switch (ios->bus_width) { + case MMC_BUS_WIDTH_8: + config2 |= SD_CONFIG2_BB; + break; case MMC_BUS_WIDTH_4: + config2 &= ~SD_CONFIG2_BB; config2 |= SD_CONFIG2_WB; break; case MMC_BUS_WIDTH_1: - config2 &= ~SD_CONFIG2_WB; + config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB); break; } au_writel(config2, HOST_CONFIG2(host)); @@ -943,7 +948,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) struct mmc_host *mmc; struct au1xmmc_host *host; struct resource *r; - int ret; + int ret, iflag; mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); if (!mmc) { @@ -982,37 +987,43 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no IRQ defined\n"); goto out3; } - host->irq = r->start; - /* IRQ is shared among both SD controllers */ - ret = request_irq(host->irq, au1xmmc_irq, IRQF_SHARED, - DRIVER_NAME, host); - if (ret) { - dev_err(&pdev->dev, "cannot grab IRQ\n"); - goto out3; - } mmc->ops = &au1xmmc_ops; mmc->f_min = 450000; mmc->f_max = 24000000; + mmc->max_blk_size = 2048; + mmc->max_blk_count = 512; + + mmc->ocr_avail = AU1XMMC_OCR; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + + iflag = IRQF_SHARED; /* Au1100/Au1200: one int for both ctrls */ + switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1100: mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; break; case ALCHEMY_CPU_AU1200: mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; - mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT; + break; + case ALCHEMY_CPU_AU1300: + iflag = 0; /* nothing is shared */ + mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE; + mmc->f_max = 52000000; + if (host->ioarea->start == AU1100_SD0_PHYS_ADDR) + mmc->caps |= MMC_CAP_8_BIT_DATA; break; } - mmc->max_blk_size = 2048; - mmc->max_blk_count = 512; - - mmc->ocr_avail = AU1XMMC_OCR; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host); + if (ret) { + dev_err(&pdev->dev, "cannot grab IRQ\n"); + goto out3; + } host->status = HOST_S_IDLE; diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index 0371bf502249..03666174ca48 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -627,17 +627,7 @@ static struct platform_driver sdh_driver = { }, }; -static int __init sdh_init(void) -{ - return platform_driver_register(&sdh_driver); -} -module_init(sdh_init); - -static void __exit sdh_exit(void) -{ - platform_driver_unregister(&sdh_driver); -} -module_exit(sdh_exit); +module_platform_driver(sdh_driver); MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver"); MODULE_AUTHOR("Cliff Cai, Roy Huang"); diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index ce2a47b71dd6..83693fd7c6b3 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -780,18 +780,7 @@ static struct platform_driver cb710_mmc_driver = { #endif }; -static int __init cb710_mmc_init_module(void) -{ - return platform_driver_register(&cb710_mmc_driver); -} - -static void __exit cb710_mmc_cleanup_module(void) -{ - platform_driver_unregister(&cb710_mmc_driver); -} - -module_init(cb710_mmc_init_module); -module_exit(cb710_mmc_cleanup_module); +module_platform_driver(cb710_mmc_driver); MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>"); MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part"); diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 3aaeb0841914..0e342793ff14 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -588,11 +588,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot) mci_writel(host, CTYPE, (slot->ctype << slot->id)); } -static void dw_mci_start_request(struct dw_mci *host, - struct dw_mci_slot *slot) +static void __dw_mci_start_request(struct dw_mci *host, + struct dw_mci_slot *slot, + struct mmc_command *cmd) { struct mmc_request *mrq; - struct mmc_command *cmd; struct mmc_data *data; u32 cmdflags; @@ -610,14 +610,13 @@ static void dw_mci_start_request(struct dw_mci *host, host->completed_events = 0; host->data_status = 0; - data = mrq->data; + data = cmd->data; if (data) { dw_mci_set_timeout(host); mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BLKSIZ, data->blksz); } - cmd = mrq->cmd; cmdflags = dw_mci_prepare_command(slot->mmc, cmd); /* this is the first command, send the initialization clock */ @@ -635,6 +634,16 @@ static void dw_mci_start_request(struct dw_mci *host, host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); } +static void dw_mci_start_request(struct dw_mci *host, + struct dw_mci_slot *slot) +{ + struct mmc_request *mrq = slot->mrq; + struct mmc_command *cmd; + + cmd = mrq->sbc ? mrq->sbc : mrq->cmd; + __dw_mci_start_request(host, slot, cmd); +} + /* must be called with host->lock held */ static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot, struct mmc_request *mrq) @@ -698,12 +707,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; } + regs = mci_readl(slot->host, UHS_REG); + /* DDR mode set */ - if (ios->timing == MMC_TIMING_UHS_DDR50) { - regs = mci_readl(slot->host, UHS_REG); + if (ios->timing == MMC_TIMING_UHS_DDR50) regs |= (0x1 << slot->id) << 16; - mci_writel(slot->host, UHS_REG, regs); - } + else + regs &= ~(0x1 << slot->id) << 16; + + mci_writel(slot->host, UHS_REG, regs); if (ios->clock) { /* @@ -889,7 +901,14 @@ static void dw_mci_tasklet_func(unsigned long priv) cmd = host->cmd; host->cmd = NULL; set_bit(EVENT_CMD_COMPLETE, &host->completed_events); - dw_mci_command_complete(host, host->mrq->cmd); + dw_mci_command_complete(host, cmd); + if (cmd == host->mrq->sbc && !cmd->error) { + prev_state = state = STATE_SENDING_CMD; + __dw_mci_start_request(host, host->cur_slot, + host->mrq->cmd); + goto unlock; + } + if (!host->mrq->data || cmd->error) { dw_mci_request_end(host, host->mrq); goto unlock; @@ -967,6 +986,12 @@ static void dw_mci_tasklet_func(unsigned long priv) goto unlock; } + if (host->mrq->sbc && !data->error) { + data->stop->error = 0; + dw_mci_request_end(host, host->mrq); + goto unlock; + } + prev_state = state = STATE_SENDING_STOP; if (!data->error) send_stop_cmd(host, data); @@ -1678,8 +1703,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->caps) mmc->caps = host->pdata->caps; - else - mmc->caps = 0; + + if (host->pdata->caps2) + mmc->caps2 = host->pdata->caps2; if (host->pdata->get_bus_wd) if (host->pdata->get_bus_wd(slot->id) >= 4) @@ -1923,7 +1949,7 @@ static int dw_mci_probe(struct platform_device *pdev) * should put it in the platform data. */ fifo_size = mci_readl(host, FIFOTH); - fifo_size = 1 + ((fifo_size >> 16) & 0x7ff); + fifo_size = 1 + ((fifo_size >> 16) & 0xfff); } else { fifo_size = host->pdata->fifo_depth; } @@ -2062,14 +2088,14 @@ static int __exit dw_mci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * TODO: we should probably disable the clock to the card in the suspend path. */ -static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) +static int dw_mci_suspend(struct device *dev) { int i, ret; - struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci *host = dev_get_drvdata(dev); for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; @@ -2092,10 +2118,10 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) return 0; } -static int dw_mci_resume(struct platform_device *pdev) +static int dw_mci_resume(struct device *dev) { int i, ret; - struct dw_mci *host = platform_get_drvdata(pdev); + struct dw_mci *host = dev_get_drvdata(dev); if (host->vmmc) regulator_enable(host->vmmc); @@ -2103,7 +2129,7 @@ static int dw_mci_resume(struct platform_device *pdev) if (host->dma_ops->init) host->dma_ops->init(host); - if (!mci_wait_reset(&pdev->dev, host)) { + if (!mci_wait_reset(dev, host)) { ret = -ENODEV; return ret; } @@ -2131,14 +2157,15 @@ static int dw_mci_resume(struct platform_device *pdev) #else #define dw_mci_suspend NULL #define dw_mci_resume NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume); static struct platform_driver dw_mci_driver = { .remove = __exit_p(dw_mci_remove), - .suspend = dw_mci_suspend, - .resume = dw_mci_resume, .driver = { .name = "dw_mmc", + .pm = &dw_mci_pmops, }, }; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 72c071f6e001..df392a1143f2 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -126,7 +126,7 @@ #define SDMMC_CMD_RESP_EXP BIT(6) #define SDMMC_CMD_INDX(n) ((n) & 0x1F) /* Status register defines */ -#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FF) +#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) /* Internal DMAC interrupt defines */ #define SDMMC_IDMAC_INT_AI BIT(9) #define SDMMC_IDMAC_INT_NI BIT(8) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 74218ad677e4..c8852a8128a9 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1012,17 +1012,7 @@ static struct platform_driver jz4740_mmc_driver = { }, }; -static int __init jz4740_mmc_init(void) -{ - return platform_driver_register(&jz4740_mmc_driver); -} -module_init(jz4740_mmc_init); - -static void __exit jz4740_mmc_exit(void) -{ - platform_driver_unregister(&jz4740_mmc_driver); -} -module_exit(jz4740_mmc_exit); +module_platform_driver(jz4740_mmc_driver); MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 92946b84e9fa..273306c68d58 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1525,7 +1525,6 @@ static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { static struct spi_driver mmc_spi_driver = { .driver = { .name = "mmc_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = mmc_spi_of_match_table, }, diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fa8dd2fda4b2..ece03b491c7d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1245,6 +1245,7 @@ static int __devinit mmci_probe(struct amba_device *dev, if (host->vcc == NULL) mmc->ocr_avail = plat->ocr_mask; mmc->caps = plat->capabilities; + mmc->caps2 = plat->capabilities2; /* * We can do SGIO diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 80d8eb143b48..1d14cda95e56 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -689,8 +689,8 @@ msmsdcc_pio_irq(int irq, void *dev_id) /* Map the current scatter buffer */ local_irq_save(flags); - buffer = kmap_atomic(sg_page(host->pio.sg), - KM_BIO_SRC_IRQ) + host->pio.sg->offset; + buffer = kmap_atomic(sg_page(host->pio.sg)) + + host->pio.sg->offset; buffer += host->pio.sg_off; remain = host->pio.sg->length - host->pio.sg_off; len = 0; @@ -700,7 +700,7 @@ msmsdcc_pio_irq(int irq, void *dev_id) len = msmsdcc_pio_write(host, buffer, remain, status); /* Unmap the buffer */ - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); + kunmap_atomic(buffer); local_irq_restore(flags); host->pio.sg_off += len; @@ -1480,18 +1480,7 @@ static struct platform_driver msmsdcc_driver = { }, }; -static int __init msmsdcc_init(void) -{ - return platform_driver_register(&msmsdcc_driver); -} - -static void __exit msmsdcc_exit(void) -{ - platform_driver_unregister(&msmsdcc_driver); -} - -module_init(msmsdcc_init); -module_exit(msmsdcc_exit); +module_platform_driver(msmsdcc_driver); MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 8e0fbe994047..7088b40f9579 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1047,18 +1047,7 @@ static struct platform_driver mxcmci_driver = { } }; -static int __init mxcmci_init(void) -{ - return platform_driver_register(&mxcmci_driver); -} - -static void __exit mxcmci_exit(void) -{ - platform_driver_unregister(&mxcmci_driver); -} - -module_init(mxcmci_init); -module_exit(mxcmci_exit); +module_platform_driver(mxcmci_driver); MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 973011f9a298..4e2e019dd5c9 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -855,18 +855,7 @@ static struct platform_driver mxs_mmc_driver = { }, }; -static int __init mxs_mmc_init(void) -{ - return platform_driver_register(&mxs_mmc_driver); -} - -static void __exit mxs_mmc_exit(void) -{ - platform_driver_unregister(&mxs_mmc_driver); -} - -module_init(mxs_mmc_init); -module_exit(mxs_mmc_exit); +module_platform_driver(mxs_mmc_driver); MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral"); MODULE_AUTHOR("Freescale Semiconductor"); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index d1fb561e089d..fd0c661bbad3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -24,7 +24,6 @@ #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> -#include <linux/workqueue.h> #include <linux/timer.h> #include <linux/clk.h> #include <linux/mmc/host.h> @@ -120,7 +119,6 @@ #define MMC_AUTOSUSPEND_DELAY 100 #define MMC_TIMEOUT_MS 20 -#define OMAP_MMC_MASTER_CLOCK 96000000 #define OMAP_MMC_MIN_CLOCK 400000 #define OMAP_MMC_MAX_CLOCK 52000000 #define DRIVER_NAME "omap_hsmmc" @@ -163,7 +161,6 @@ struct omap_hsmmc_host { */ struct regulator *vcc; struct regulator *vcc_aux; - struct work_struct mmc_carddetect_work; void __iomem *base; resource_size_t mapbase; spinlock_t irq_lock; /* Prevent races with irq handler */ @@ -598,12 +595,12 @@ static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host) } /* Calculate divisor for the given clock frequency */ -static u16 calc_divisor(struct mmc_ios *ios) +static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios) { u16 dsor = 0; if (ios->clock) { - dsor = DIV_ROUND_UP(OMAP_MMC_MASTER_CLOCK, ios->clock); + dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock); if (dsor > 250) dsor = 250; } @@ -623,7 +620,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) regval = OMAP_HSMMC_READ(host->base, SYSCTL); regval = regval & ~(CLKD_MASK | DTO_MASK); - regval = regval | (calc_divisor(ios) << 6) | (DTO << 16); + regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16); OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); @@ -1280,17 +1277,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) } /* - * Work Item to notify the core about card insertion/removal + * irq handler to notify the core about card insertion/removal */ -static void omap_hsmmc_detect(struct work_struct *work) +static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) { - struct omap_hsmmc_host *host = - container_of(work, struct omap_hsmmc_host, mmc_carddetect_work); + struct omap_hsmmc_host *host = dev_id; struct omap_mmc_slot_data *slot = &mmc_slot(host); int carddetect; if (host->suspended) - return; + return IRQ_HANDLED; sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); @@ -1305,19 +1301,6 @@ static void omap_hsmmc_detect(struct work_struct *work) mmc_detect_change(host->mmc, (HZ * 200) / 1000); else mmc_detect_change(host->mmc, (HZ * 50) / 1000); -} - -/* - * ISR for handling card insertion and removal - */ -static irqreturn_t omap_hsmmc_cd_handler(int irq, void *dev_id) -{ - struct omap_hsmmc_host *host = (struct omap_hsmmc_host *)dev_id; - - if (host->suspended) - return IRQ_HANDLED; - schedule_work(&host->mmc_carddetect_work); - return IRQ_HANDLED; } @@ -1919,7 +1902,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) host->next_data.cookie = 1; platform_set_drvdata(pdev, host); - INIT_WORK(&host->mmc_carddetect_work, omap_hsmmc_detect); mmc->ops = &omap_hsmmc_ops; @@ -2049,10 +2031,11 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) /* Request IRQ for card detect */ if ((mmc_slot(host).card_detect_irq)) { - ret = request_irq(mmc_slot(host).card_detect_irq, - omap_hsmmc_cd_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - mmc_hostname(mmc), host); + ret = request_threaded_irq(mmc_slot(host).card_detect_irq, + NULL, + omap_hsmmc_detect, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + mmc_hostname(mmc), host); if (ret) { dev_dbg(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ\n"); @@ -2131,7 +2114,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev) free_irq(host->irq, host); if (mmc_slot(host).card_detect_irq) free_irq(mmc_slot(host).card_detect_irq, host); - flush_work_sync(&host->mmc_carddetect_work); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); @@ -2178,7 +2160,6 @@ static int omap_hsmmc_suspend(struct device *dev) return ret; } } - cancel_work_sync(&host->mmc_carddetect_work); ret = mmc_suspend_host(host->mmc); if (ret) { diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index fc4356e00d46..cb2dc0e75ba7 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -872,18 +872,7 @@ static struct platform_driver pxamci_driver = { }, }; -static int __init pxamci_init(void) -{ - return platform_driver_register(&pxamci_driver); -} - -static void __exit pxamci_exit(void) -{ - platform_driver_unregister(&pxamci_driver); -} - -module_init(pxamci_init); -module_exit(pxamci_exit); +module_platform_driver(pxamci_driver); MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 720f99334a7f..1bcfd6dbb5cc 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1914,18 +1914,7 @@ static struct platform_driver s3cmci_driver = { .shutdown = s3cmci_shutdown, }; -static int __init s3cmci_init(void) -{ - return platform_driver_register(&s3cmci_driver); -} - -static void __exit s3cmci_exit(void) -{ - platform_driver_unregister(&s3cmci_driver); -} - -module_init(s3cmci_init); -module_exit(s3cmci_exit); +module_platform_driver(s3cmci_driver); MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index b4257e700617..28a870804f60 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -115,17 +115,7 @@ static struct platform_driver sdhci_cns3xxx_driver = { .remove = __devexit_p(sdhci_cns3xxx_remove), }; -static int __init sdhci_cns3xxx_init(void) -{ - return platform_driver_register(&sdhci_cns3xxx_driver); -} -module_init(sdhci_cns3xxx_init); - -static void __exit sdhci_cns3xxx_exit(void) -{ - platform_driver_unregister(&sdhci_cns3xxx_driver); -} -module_exit(sdhci_cns3xxx_exit); +module_platform_driver(sdhci_cns3xxx_driver); MODULE_DESCRIPTION("SDHCI driver for CNS3xxx"); MODULE_AUTHOR("Scott Shu, " diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index a81312c91f70..46fd1fd1b605 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -88,17 +88,7 @@ static struct platform_driver sdhci_dove_driver = { .remove = __devexit_p(sdhci_dove_remove), }; -static int __init sdhci_dove_init(void) -{ - return platform_driver_register(&sdhci_dove_driver); -} -module_init(sdhci_dove_init); - -static void __exit sdhci_dove_exit(void) -{ - platform_driver_unregister(&sdhci_dove_driver); -} -module_exit(sdhci_dove_exit); +module_platform_driver(sdhci_dove_driver); MODULE_DESCRIPTION("SDHCI driver for Dove"); MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, " diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 38ebc4ea259f..d601e41af282 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -606,17 +606,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = { .remove = __devexit_p(sdhci_esdhc_imx_remove), }; -static int __init sdhci_esdhc_imx_init(void) -{ - return platform_driver_register(&sdhci_esdhc_imx_driver); -} -module_init(sdhci_esdhc_imx_init); - -static void __exit sdhci_esdhc_imx_exit(void) -{ - platform_driver_unregister(&sdhci_esdhc_imx_driver); -} -module_exit(sdhci_esdhc_imx_exit); +module_platform_driver(sdhci_esdhc_imx_driver); MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index c3b08f111942..b97b2f5dafdb 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -73,7 +73,7 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) | (div << ESDHC_DIVIDER_SHIFT) | (pre_div << ESDHC_PREDIV_SHIFT)); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - mdelay(100); + mdelay(1); out: host->clock = clock; } diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 01e5f627e0f0..ff4adc018041 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -131,17 +131,7 @@ static struct platform_driver sdhci_esdhc_driver = { .remove = __devexit_p(sdhci_esdhc_remove), }; -static int __init sdhci_esdhc_init(void) -{ - return platform_driver_register(&sdhci_esdhc_driver); -} -module_init(sdhci_esdhc_init); - -static void __exit sdhci_esdhc_exit(void) -{ - platform_driver_unregister(&sdhci_esdhc_driver); -} -module_exit(sdhci_esdhc_exit); +module_platform_driver(sdhci_esdhc_driver); MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC"); MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, " diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 3619adc7d9fc..0ce088ae0228 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -93,17 +93,7 @@ static struct platform_driver sdhci_hlwd_driver = { .remove = __devexit_p(sdhci_hlwd_remove), }; -static int __init sdhci_hlwd_init(void) -{ - return platform_driver_register(&sdhci_hlwd_driver); -} -module_init(sdhci_hlwd_init); - -static void __exit sdhci_hlwd_exit(void) -{ - platform_driver_unregister(&sdhci_hlwd_driver); -} -module_exit(sdhci_hlwd_exit); +module_platform_driver(sdhci_hlwd_driver); MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver"); MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz"); diff --git a/drivers/mmc/host/sdhci-pci-data.c b/drivers/mmc/host/sdhci-pci-data.c new file mode 100644 index 000000000000..a611217769f5 --- /dev/null +++ b/drivers/mmc/host/sdhci-pci-data.c @@ -0,0 +1,5 @@ +#include <linux/module.h> +#include <linux/mmc/sdhci-pci-data.h> + +struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno); +EXPORT_SYMBOL_GPL(sdhci_pci_get_data); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 6878a94626bc..7165e6a09274 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -23,8 +23,8 @@ #include <linux/scatterlist.h> #include <linux/io.h> #include <linux/gpio.h> -#include <linux/sfi.h> #include <linux/pm_runtime.h> +#include <linux/mmc/sdhci-pci-data.h> #include "sdhci.h" @@ -61,6 +61,7 @@ struct sdhci_pci_fixes { struct sdhci_pci_slot { struct sdhci_pci_chip *chip; struct sdhci_host *host; + struct sdhci_pci_data *data; int pci_bar; int rst_n_gpio; @@ -171,32 +172,9 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) return 0; } -/* Medfield eMMC hardware reset GPIOs */ -static int mfd_emmc0_rst_gpio = -EINVAL; -static int mfd_emmc1_rst_gpio = -EINVAL; - -static int mfd_emmc_gpio_parse(struct sfi_table_header *table) -{ - struct sfi_table_simple *sb = (struct sfi_table_simple *)table; - struct sfi_gpio_table_entry *entry; - int i, num; - - num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); - entry = (struct sfi_gpio_table_entry *)sb->pentry; - - for (i = 0; i < num; i++, entry++) { - if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN)) - mfd_emmc0_rst_gpio = entry->pin_no; - else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN)) - mfd_emmc1_rst_gpio = entry->pin_no; - } - - return 0; -} - #ifdef CONFIG_PM_RUNTIME -static irqreturn_t mfd_sd_cd(int irq, void *dev_id) +static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id) { struct sdhci_pci_slot *slot = dev_id; struct sdhci_host *host = slot->host; @@ -205,15 +183,16 @@ static irqreturn_t mfd_sd_cd(int irq, void *dev_id) return IRQ_HANDLED; } -#define MFLD_SD_CD_PIN 69 - -static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) +static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) { - int err, irq, gpio = MFLD_SD_CD_PIN; + int err, irq, gpio = slot->cd_gpio; slot->cd_gpio = -EINVAL; slot->cd_irq = -EINVAL; + if (!gpio_is_valid(gpio)) + return; + err = gpio_request(gpio, "sd_cd"); if (err < 0) goto out; @@ -226,72 +205,53 @@ static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) if (irq < 0) goto out_free; - err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING | + err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "sd_cd", slot); if (err) goto out_free; slot->cd_gpio = gpio; slot->cd_irq = irq; - slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION; - return 0; + return; out_free: gpio_free(gpio); out: dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); - return 0; } -static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead) +static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) { if (slot->cd_irq >= 0) free_irq(slot->cd_irq, slot); - gpio_free(slot->cd_gpio); + if (gpio_is_valid(slot->cd_gpio)) + gpio_free(slot->cd_gpio); } #else -#define mfd_sd_probe_slot NULL -#define mfd_sd_remove_slot NULL +static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot) +{ +} + +static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot) +{ +} #endif static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) { - const char *name = NULL; - int gpio = -EINVAL; - - sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse); - - switch (slot->chip->pdev->device) { - case PCI_DEVICE_ID_INTEL_MFD_EMMC0: - gpio = mfd_emmc0_rst_gpio; - name = "eMMC0_reset"; - break; - case PCI_DEVICE_ID_INTEL_MFD_EMMC1: - gpio = mfd_emmc1_rst_gpio; - name = "eMMC1_reset"; - break; - } - - if (!gpio_request(gpio, name)) { - gpio_direction_output(gpio, 1); - slot->rst_n_gpio = gpio; - slot->host->mmc->caps |= MMC_CAP_HW_RESET; - } - slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; - slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; - return 0; } -static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead) +static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot) { - gpio_free(slot->rst_n_gpio); + slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD; + return 0; } static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { @@ -307,20 +267,18 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, - .probe_slot = mfd_sd_probe_slot, - .remove_slot = mfd_sd_remove_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, + .probe_slot = mfd_sdio_probe_slot, }; static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .allow_runtime_pm = true, .probe_slot = mfd_emmc_probe_slot, - .remove_slot = mfd_emmc_remove_slot, }; /* O2Micro extra registers */ @@ -1012,11 +970,8 @@ static int sdhci_pci_suspend(struct device *dev) ret = sdhci_suspend_host(slot->host); - if (ret) { - for (i--; i >= 0; i--) - sdhci_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_suspend; slot_pm_flags = slot->host->mmc->pm_flags; if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ) @@ -1027,11 +982,8 @@ static int sdhci_pci_suspend(struct device *dev) if (chip->fixes && chip->fixes->suspend) { ret = chip->fixes->suspend(chip); - if (ret) { - for (i = chip->num_slots - 1; i >= 0; i--) - sdhci_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_suspend; } pci_save_state(pdev); @@ -1048,6 +1000,11 @@ static int sdhci_pci_suspend(struct device *dev) } return 0; + +err_pci_suspend: + while (--i >= 0) + sdhci_resume_host(chip->slots[i]->host); + return ret; } static int sdhci_pci_resume(struct device *dev) @@ -1113,23 +1070,22 @@ static int sdhci_pci_runtime_suspend(struct device *dev) ret = sdhci_runtime_suspend_host(slot->host); - if (ret) { - for (i--; i >= 0; i--) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_runtime_suspend; } if (chip->fixes && chip->fixes->suspend) { ret = chip->fixes->suspend(chip); - if (ret) { - for (i = chip->num_slots - 1; i >= 0; i--) - sdhci_runtime_resume_host(chip->slots[i]->host); - return ret; - } + if (ret) + goto err_pci_runtime_suspend; } return 0; + +err_pci_runtime_suspend: + while (--i >= 0) + sdhci_runtime_resume_host(chip->slots[i]->host); + return ret; } static int sdhci_pci_runtime_resume(struct device *dev) @@ -1190,11 +1146,12 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { \*****************************************************************************/ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( - struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar) + struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, + int slotno) { struct sdhci_pci_slot *slot; struct sdhci_host *host; - int ret; + int ret, bar = first_bar + slotno; if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); @@ -1228,6 +1185,23 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( slot->host = host; slot->pci_bar = bar; slot->rst_n_gpio = -EINVAL; + slot->cd_gpio = -EINVAL; + + /* Retrieve platform data if there is any */ + if (*sdhci_pci_get_data) + slot->data = sdhci_pci_get_data(pdev, slotno); + + if (slot->data) { + if (slot->data->setup) { + ret = slot->data->setup(slot->data); + if (ret) { + dev_err(&pdev->dev, "platform setup failed\n"); + goto free; + } + } + slot->rst_n_gpio = slot->data->rst_n_gpio; + slot->cd_gpio = slot->data->cd_gpio; + } host->hw_name = "PCI"; host->ops = &sdhci_pci_ops; @@ -1238,7 +1212,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc)); if (ret) { dev_err(&pdev->dev, "cannot request region\n"); - goto free; + goto cleanup; } host->ioaddr = pci_ioremap_bar(pdev, bar); @@ -1254,15 +1228,30 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( goto unmap; } + if (gpio_is_valid(slot->rst_n_gpio)) { + if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) { + gpio_direction_output(slot->rst_n_gpio, 1); + slot->host->mmc->caps |= MMC_CAP_HW_RESET; + } else { + dev_warn(&pdev->dev, "failed to request rst_n_gpio\n"); + slot->rst_n_gpio = -EINVAL; + } + } + host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; ret = sdhci_add_host(host); if (ret) goto remove; + sdhci_pci_add_own_cd(slot); + return slot; remove: + if (gpio_is_valid(slot->rst_n_gpio)) + gpio_free(slot->rst_n_gpio); + if (chip->fixes && chip->fixes->remove_slot) chip->fixes->remove_slot(slot, 0); @@ -1272,6 +1261,10 @@ unmap: release: pci_release_region(pdev, bar); +cleanup: + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + free: sdhci_free_host(host); @@ -1283,6 +1276,8 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) int dead; u32 scratch; + sdhci_pci_remove_own_cd(slot); + dead = 0; scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS); if (scratch == (u32)-1) @@ -1290,9 +1285,15 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_remove_host(slot->host, dead); + if (gpio_is_valid(slot->rst_n_gpio)) + gpio_free(slot->rst_n_gpio); + if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); + if (slot->data && slot->data->cleanup) + slot->data->cleanup(slot->data); + pci_release_region(slot->chip->pdev, slot->pci_bar); sdhci_free_host(slot->host); @@ -1379,7 +1380,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, slots = chip->num_slots; /* Quirk may have changed this */ for (i = 0; i < slots; i++) { - slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i); + slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i); if (IS_ERR(slot)) { for (i--; i >= 0; i--) sdhci_pci_remove_slot(chip->slots[i]); diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 7a039c3cb1f1..dbb75bfbcffb 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -223,18 +223,8 @@ static struct platform_driver sdhci_pxav2_driver = { .probe = sdhci_pxav2_probe, .remove = __devexit_p(sdhci_pxav2_remove), }; -static int __init sdhci_pxav2_init(void) -{ - return platform_driver_register(&sdhci_pxav2_driver); -} - -static void __exit sdhci_pxav2_exit(void) -{ - platform_driver_unregister(&sdhci_pxav2_driver); -} -module_init(sdhci_pxav2_init); -module_exit(sdhci_pxav2_exit); +module_platform_driver(sdhci_pxav2_driver); MODULE_DESCRIPTION("SDHCI driver for pxav2"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 15673a7ee6a5..f29695683556 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -269,18 +269,8 @@ static struct platform_driver sdhci_pxav3_driver = { .probe = sdhci_pxav3_probe, .remove = __devexit_p(sdhci_pxav3_remove), }; -static int __init sdhci_pxav3_init(void) -{ - return platform_driver_register(&sdhci_pxav3_driver); -} - -static void __exit sdhci_pxav3_exit(void) -{ - platform_driver_unregister(&sdhci_pxav3_driver); -} -module_init(sdhci_pxav3_init); -module_exit(sdhci_pxav3_exit); +module_platform_driver(sdhci_pxav3_driver); MODULE_DESCRIPTION("SDHCI driver for pxav3"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 9a20d1f55bb7..1af756ee0f9a 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -80,7 +80,7 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host) tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK; tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT; - writel(tmp, host->ioaddr + 0x80); + writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2); } } @@ -521,6 +521,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; + if (pdata->pm_caps) + host->mmc->pm_caps |= pdata->pm_caps; + host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE); @@ -654,18 +657,7 @@ static struct platform_driver sdhci_s3c_driver = { }, }; -static int __init sdhci_s3c_init(void) -{ - return platform_driver_register(&sdhci_s3c_driver); -} - -static void __exit sdhci_s3c_exit(void) -{ - platform_driver_unregister(&sdhci_s3c_driver); -} - -module_init(sdhci_s3c_init); -module_exit(sdhci_s3c_exit); +module_platform_driver(sdhci_s3c_driver); MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue"); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 63cc8b6a1c9e..b7f8b33c5f19 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -21,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/slab.h> #include <linux/mmc/host.h> #include <linux/mmc/sdhci-spear.h> @@ -271,26 +272,54 @@ static int __devexit sdhci_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int sdhci_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct spear_sdhci *sdhci = dev_get_platdata(dev); + int ret; + + ret = sdhci_suspend_host(host); + if (!ret) + clk_disable(sdhci->clk); + + return ret; +} + +static int sdhci_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct spear_sdhci *sdhci = dev_get_platdata(dev); + int ret; + + ret = clk_enable(sdhci->clk); + if (ret) { + dev_dbg(dev, "Resume: Error enabling clock\n"); + return ret; + } + + return sdhci_resume_host(host); +} + +const struct dev_pm_ops sdhci_pm_ops = { + .suspend = sdhci_suspend, + .resume = sdhci_resume, +}; +#endif + static struct platform_driver sdhci_driver = { .driver = { .name = "sdhci", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &sdhci_pm_ops, +#endif }, .probe = sdhci_probe, .remove = __devexit_p(sdhci_remove), }; -static int __init sdhci_init(void) -{ - return platform_driver_register(&sdhci_driver); -} -module_init(sdhci_init); - -static void __exit sdhci_exit(void) -{ - platform_driver_unregister(&sdhci_driver); -} -module_exit(sdhci_exit); +module_platform_driver(sdhci_driver); MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver"); MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>"); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index e2e18d3f949c..78a36eba4df0 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -324,17 +324,7 @@ static struct platform_driver sdhci_tegra_driver = { .remove = __devexit_p(sdhci_tegra_remove), }; -static int __init sdhci_tegra_init(void) -{ - return platform_driver_register(&sdhci_tegra_driver); -} -module_init(sdhci_tegra_init); - -static void __exit sdhci_tegra_exit(void) -{ - platform_driver_unregister(&sdhci_tegra_driver); -} -module_exit(sdhci_tegra_exit); +module_platform_driver(sdhci_tegra_driver); MODULE_DESCRIPTION("SDHCI driver for Tegra"); MODULE_AUTHOR(" Google, Inc."); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 19ed580f2cab..8d66706824a6 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -49,7 +49,7 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_send_command(struct sdhci_host *, struct mmc_command *); static void sdhci_finish_command(struct sdhci_host *); -static int sdhci_execute_tuning(struct mmc_host *mmc); +static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_tuning_timer(unsigned long data); #ifdef CONFIG_PM_RUNTIME @@ -146,10 +146,8 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) { u32 present, irqs; - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - return; - - if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION) + if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || + !mmc_card_is_removable(host->mmc)) return; present = sdhci_readl(host, SDHCI_PRESENT_STATE) & @@ -214,6 +212,11 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); + + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { + if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL)) + host->ops->enable_dma(host); + } } static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); @@ -423,12 +426,12 @@ static void sdhci_transfer_pio(struct sdhci_host *host) static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + return kmap_atomic(sg_page(sg)) + sg->offset; } static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) { - kunmap_atomic(buffer, KM_BIO_SRC_IRQ); + kunmap_atomic(buffer); local_irq_restore(*flags); } @@ -1016,7 +1019,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) flags |= SDHCI_CMD_INDEX; /* CMD19 is special in that the Data Present Select should be set */ - if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK)) + if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK || + cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200) flags |= SDHCI_CMD_DATA; sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); @@ -1066,12 +1070,15 @@ static void sdhci_finish_command(struct sdhci_host *host) static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { int div = 0; /* Initialized for compiler warning */ + int real_div = div, clk_mul = 1; u16 clk = 0; unsigned long timeout; - if (clock == host->clock) + if (clock && clock == host->clock) return; + host->mmc->actual_clock = 0; + if (host->ops->set_clock) { host->ops->set_clock(host, clock); if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) @@ -1109,6 +1116,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) * Control register. */ clk = SDHCI_PROG_CLOCK_MODE; + real_div = div; + clk_mul = host->clk_mul; div--; } } else { @@ -1122,6 +1131,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) break; } } + real_div = div; div >>= 1; } } else { @@ -1130,9 +1140,13 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) if ((host->max_clk / div) <= clock) break; } + real_div = div; div >>= 1; } + if (real_div) + host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div; + clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; @@ -1160,7 +1174,7 @@ out: host->clock = clock; } -static void sdhci_set_power(struct sdhci_host *host, unsigned short power) +static int sdhci_set_power(struct sdhci_host *host, unsigned short power) { u8 pwr = 0; @@ -1183,13 +1197,13 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) } if (host->pwr == pwr) - return; + return -1; host->pwr = pwr; if (pwr == 0) { sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); - return; + return 0; } /* @@ -1216,6 +1230,8 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) */ if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER) mdelay(10); + + return power; } /*****************************************************************************\ @@ -1277,7 +1293,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) if ((host->flags & SDHCI_NEEDS_RETUNING) && !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { spin_unlock_irqrestore(&host->lock, flags); - sdhci_execute_tuning(mmc); + sdhci_execute_tuning(mmc, mrq->cmd->opcode); spin_lock_irqsave(&host->lock, flags); /* Restore original mmc_request structure */ @@ -1297,12 +1313,17 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) { unsigned long flags; + int vdd_bit = -1; u8 ctrl; spin_lock_irqsave(&host->lock, flags); - if (host->flags & SDHCI_DEVICE_DEAD) - goto out; + if (host->flags & SDHCI_DEVICE_DEAD) { + spin_unlock_irqrestore(&host->lock, flags); + if (host->vmmc && ios->power_mode == MMC_POWER_OFF) + mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); + return; + } /* * Reset the chip on each power off. @@ -1316,9 +1337,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_set_clock(host, ios->clock); if (ios->power_mode == MMC_POWER_OFF) - sdhci_set_power(host, -1); + vdd_bit = sdhci_set_power(host, -1); else - sdhci_set_power(host, ios->vdd); + vdd_bit = sdhci_set_power(host, ios->vdd); + + if (host->vmmc && vdd_bit != -1) { + spin_unlock_irqrestore(&host->lock, flags); + mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit); + spin_lock_irqsave(&host->lock, flags); + } if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); @@ -1361,11 +1388,11 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) unsigned int clock; /* In case of UHS-I modes, set High Speed Enable */ - if ((ios->timing == MMC_TIMING_UHS_SDR50) || + if ((ios->timing == MMC_TIMING_MMC_HS200) || + (ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_DDR50) || - (ios->timing == MMC_TIMING_UHS_SDR25) || - (ios->timing == MMC_TIMING_UHS_SDR12)) + (ios->timing == MMC_TIMING_UHS_SDR25)) ctrl |= SDHCI_CTRL_HISPD; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); @@ -1415,7 +1442,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* Select Bus Speed Mode for host */ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; - if (ios->timing == MMC_TIMING_UHS_SDR12) + if (ios->timing == MMC_TIMING_MMC_HS200) + ctrl_2 |= SDHCI_CTRL_HS_SDR200; + else if (ios->timing == MMC_TIMING_UHS_SDR12) ctrl_2 |= SDHCI_CTRL_UHS_SDR12; else if (ios->timing == MMC_TIMING_UHS_SDR25) ctrl_2 |= SDHCI_CTRL_UHS_SDR25; @@ -1443,7 +1472,6 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS) sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); -out: mmiowb(); spin_unlock_irqrestore(&host->lock, flags); } @@ -1663,7 +1691,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, return err; } -static int sdhci_execute_tuning(struct mmc_host *mmc) +static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct sdhci_host *host; u16 ctrl; @@ -1671,6 +1699,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) int tuning_loop_counter = MAX_TUNING_LOOP; unsigned long timeout; int err = 0; + bool requires_tuning_nonuhs = false; host = mmc_priv(mmc); @@ -1681,13 +1710,19 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); /* - * Host Controller needs tuning only in case of SDR104 mode - * and for SDR50 mode when Use Tuning for SDR50 is set in + * The Host Controller needs tuning only in case of SDR104 mode + * and for SDR50 mode when Use Tuning for SDR50 is set in the * Capabilities register. + * If the Host Controller supports the HS200 mode then the + * tuning function has to be executed. */ + if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && + (host->flags & SDHCI_SDR50_NEEDS_TUNING || + host->flags & SDHCI_HS200_NEEDS_TUNING)) + requires_tuning_nonuhs = true; + if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) || - (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) && - (host->flags & SDHCI_SDR50_NEEDS_TUNING))) + requires_tuning_nonuhs) ctrl |= SDHCI_CTRL_EXEC_TUNING; else { spin_unlock(&host->lock); @@ -1723,7 +1758,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) if (!tuning_loop_counter && !timeout) break; - cmd.opcode = MMC_SEND_TUNING_BLOCK; + cmd.opcode = opcode; cmd.arg = 0; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; cmd.retries = 0; @@ -1738,7 +1773,17 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) * block to the Host Controller. So we set the block size * to 64 here. */ - sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE); + if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) { + if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), + SDHCI_BLOCK_SIZE); + else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), + SDHCI_BLOCK_SIZE); + } else { + sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), + SDHCI_BLOCK_SIZE); + } /* * The tuning block is sent by the card to the host controller. @@ -2121,12 +2166,14 @@ static void sdhci_show_adma_error(struct sdhci_host *host) { } static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { + u32 command; BUG_ON(intmask == 0); /* CMD19 generates _only_ Buffer Read Ready interrupt */ if (intmask & SDHCI_INT_DATA_AVAIL) { - if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) == - MMC_SEND_TUNING_BLOCK) { + command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)); + if (command == MMC_SEND_TUNING_BLOCK || + command == MMC_SEND_TUNING_BLOCK_HS200) { host->tuning_done = 1; wake_up(&host->buf_ready_int); return; @@ -2330,26 +2377,33 @@ out: int sdhci_suspend_host(struct sdhci_host *host) { int ret; + bool has_tuning_timer; sdhci_disable_card_detection(host); /* Disable tuning since we are suspending */ - if (host->version >= SDHCI_SPEC_300 && host->tuning_count && - host->tuning_mode == SDHCI_TUNING_MODE_1) { + has_tuning_timer = host->version >= SDHCI_SPEC_300 && + host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1; + if (has_tuning_timer) { + del_timer_sync(&host->tuning_timer); host->flags &= ~SDHCI_NEEDS_RETUNING; - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); } ret = mmc_suspend_host(host->mmc); - if (ret) + if (ret) { + if (has_tuning_timer) { + host->flags |= SDHCI_NEEDS_RETUNING; + mod_timer(&host->tuning_timer, jiffies + + host->tuning_count * HZ); + } + + sdhci_enable_card_detection(host); + return ret; + } free_irq(host->irq, host); - if (host->vmmc) - ret = regulator_disable(host->vmmc); - return ret; } @@ -2359,12 +2413,6 @@ int sdhci_resume_host(struct sdhci_host *host) { int ret; - if (host->vmmc) { - int ret = regulator_enable(host->vmmc); - if (ret) - return ret; - } - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->ops->enable_dma) host->ops->enable_dma(host); @@ -2727,10 +2775,14 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[1] & SDHCI_SUPPORT_DDR50) mmc->caps |= MMC_CAP_UHS_DDR50; - /* Does the host needs tuning for SDR50? */ + /* Does the host need tuning for SDR50? */ if (caps[1] & SDHCI_USE_SDR50_TUNING) host->flags |= SDHCI_SDR50_NEEDS_TUNING; + /* Does the host need tuning for HS200? */ + if (mmc->caps2 & MMC_CAP2_HS200) + host->flags |= SDHCI_HS200_NEEDS_TUNING; + /* Driver Type(s) (A, C, D) supported by the host */ if (caps[1] & SDHCI_DRIVER_TYPE_A) mmc->caps |= MMC_CAP_DRIVER_TYPE_A; @@ -2926,8 +2978,6 @@ int sdhci_add_host(struct sdhci_host *host) if (IS_ERR(host->vmmc)) { pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; - } else { - regulator_enable(host->vmmc); } sdhci_init(host, 0); @@ -3016,10 +3066,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_kill(&host->card_tasklet); tasklet_kill(&host->finish_tasklet); - if (host->vmmc) { - regulator_disable(host->vmmc); + if (host->vmmc) regulator_put(host->vmmc); - } kfree(host->adma_desc); kfree(host->align_buffer); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index a04d4d0c6fd2..ad265b96b75b 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -158,6 +158,7 @@ #define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 +#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */ #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index d5505f3fe2a1..4a2c5b2355f2 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -16,6 +16,33 @@ * */ +/* + * The MMCIF driver is now processing MMC requests asynchronously, according + * to the Linux MMC API requirement. + * + * The MMCIF driver processes MMC requests in up to 3 stages: command, optional + * data, and optional stop. To achieve asynchronous processing each of these + * stages is split into two halves: a top and a bottom half. The top half + * initialises the hardware, installs a timeout handler to handle completion + * timeouts, and returns. In case of the command stage this immediately returns + * control to the caller, leaving all further processing to run asynchronously. + * All further request processing is performed by the bottom halves. + * + * The bottom half further consists of a "hard" IRQ handler, an IRQ handler + * thread, a DMA completion callback, if DMA is used, a timeout work, and + * request- and stage-specific handler methods. + * + * Each bottom half run begins with either a hardware interrupt, a DMA callback + * invocation, or a timeout work run. In case of an error or a successful + * processing completion, the MMC core is informed and the request processing is + * finished. In case processing has to continue, i.e., if data has to be read + * from or written to the card, or if a stop command has to be sent, the next + * top half is called, which performs the necessary hardware handling and + * reschedules the timeout work. This returns the driver state machine into the + * bottom half waiting state. + */ + +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> @@ -123,6 +150,11 @@ #define MASK_MRBSYTO (1 << 1) #define MASK_MRSPTO (1 << 0) +#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \ + MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \ + MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \ + MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO) + /* CE_HOST_STS1 */ #define STS1_CMDSEQ (1 << 31) @@ -162,9 +194,21 @@ enum mmcif_state { STATE_IOS, }; +enum mmcif_wait_for { + MMCIF_WAIT_FOR_REQUEST, + MMCIF_WAIT_FOR_CMD, + MMCIF_WAIT_FOR_MREAD, + MMCIF_WAIT_FOR_MWRITE, + MMCIF_WAIT_FOR_READ, + MMCIF_WAIT_FOR_WRITE, + MMCIF_WAIT_FOR_READ_END, + MMCIF_WAIT_FOR_WRITE_END, + MMCIF_WAIT_FOR_STOP, +}; + struct sh_mmcif_host { struct mmc_host *mmc; - struct mmc_data *data; + struct mmc_request *mrq; struct platform_device *pd; struct sh_dmae_slave dma_slave_tx; struct sh_dmae_slave dma_slave_rx; @@ -172,11 +216,17 @@ struct sh_mmcif_host { unsigned int clk; int bus_width; bool sd_error; + bool dying; long timeout; void __iomem *addr; - struct completion intr_wait; + u32 *pio_ptr; + spinlock_t lock; /* protect sh_mmcif_host::state */ enum mmcif_state state; - spinlock_t lock; + enum mmcif_wait_for wait_for; + struct delayed_work timeout_work; + size_t blocksize; + int sg_idx; + int sg_blkidx; bool power; bool card_present; @@ -202,19 +252,21 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, static void mmcif_dma_complete(void *arg) { struct sh_mmcif_host *host = arg; + struct mmc_data *data = host->mrq->data; + dev_dbg(&host->pd->dev, "Command completed\n"); - if (WARN(!host->data, "%s: NULL data in DMA completion!\n", + if (WARN(!data, "%s: NULL data in DMA completion!\n", dev_name(&host->pd->dev))) return; - if (host->data->flags & MMC_DATA_READ) + if (data->flags & MMC_DATA_READ) dma_unmap_sg(host->chan_rx->device->dev, - host->data->sg, host->data->sg_len, + data->sg, data->sg_len, DMA_FROM_DEVICE); else dma_unmap_sg(host->chan_tx->device->dev, - host->data->sg, host->data->sg_len, + data->sg, data->sg_len, DMA_TO_DEVICE); complete(&host->dma_complete); @@ -222,13 +274,14 @@ static void mmcif_dma_complete(void *arg) static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) { - struct scatterlist *sg = host->data->sg; + struct mmc_data *data = host->mrq->data; + struct scatterlist *sg = data->sg; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, + ret = dma_map_sg(chan->device->dev, sg, data->sg_len, DMA_FROM_DEVICE); if (ret > 0) { host->dma_active = true; @@ -244,7 +297,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, host->data->sg_len, ret, cookie); + __func__, data->sg_len, ret, cookie); if (!desc) { /* DMA failed, fall back to PIO */ @@ -265,18 +318,19 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) } dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, cookie, host->data->sg_len); + desc, cookie, data->sg_len); } static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) { - struct scatterlist *sg = host->data->sg; + struct mmc_data *data = host->mrq->data; + struct scatterlist *sg = data->sg; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, + ret = dma_map_sg(chan->device->dev, sg, data->sg_len, DMA_TO_DEVICE); if (ret > 0) { host->dma_active = true; @@ -292,7 +346,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", - __func__, host->data->sg_len, ret, cookie); + __func__, data->sg_len, ret, cookie); if (!desc) { /* DMA failed, fall back to PIO */ @@ -399,7 +453,7 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); else sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & - (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16)); + ((fls(host->clk / clk) - 1) << 16)); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); } @@ -421,7 +475,7 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) static int sh_mmcif_error_manage(struct sh_mmcif_host *host) { u32 state1, state2; - int ret, timeout = 10000000; + int ret, timeout; host->sd_error = false; @@ -433,155 +487,212 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host) if (state1 & STS1_CMDSEQ) { sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); - while (1) { - timeout--; - if (timeout < 0) { - dev_err(&host->pd->dev, - "Forceed end of command sequence timeout err\n"); - return -EIO; - } + for (timeout = 10000000; timeout; timeout--) { if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) - & STS1_CMDSEQ)) + & STS1_CMDSEQ)) break; mdelay(1); } + if (!timeout) { + dev_err(&host->pd->dev, + "Forced end of command sequence timeout err\n"); + return -EIO; + } sh_mmcif_sync_reset(host); dev_dbg(&host->pd->dev, "Forced end of command sequence\n"); return -EIO; } if (state2 & STS2_CRC_ERR) { - dev_dbg(&host->pd->dev, ": Happened CRC error\n"); + dev_dbg(&host->pd->dev, ": CRC error\n"); ret = -EIO; } else if (state2 & STS2_TIMEOUT_ERR) { - dev_dbg(&host->pd->dev, ": Happened Timeout error\n"); + dev_dbg(&host->pd->dev, ": Timeout\n"); ret = -ETIMEDOUT; } else { - dev_dbg(&host->pd->dev, ": Happened End/Index error\n"); + dev_dbg(&host->pd->dev, ": End/Index error\n"); ret = -EIO; } return ret; } -static int sh_mmcif_single_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) { - struct mmc_data *data = mrq->data; - long time; - u32 blocksize, i, *p = sg_virt(data->sg); + struct mmc_data *data = host->mrq->data; + + host->sg_blkidx += host->blocksize; + + /* data->sg->length must be a multiple of host->blocksize? */ + BUG_ON(host->sg_blkidx > data->sg->length); + + if (host->sg_blkidx == data->sg->length) { + host->sg_blkidx = 0; + if (++host->sg_idx < data->sg_len) + host->pio_ptr = sg_virt(++data->sg); + } else { + host->pio_ptr = p; + } + + if (host->sg_idx == data->sg_len) + return false; + + return true; +} + +static void sh_mmcif_single_read(struct sh_mmcif_host *host, + struct mmc_request *mrq) +{ + host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK) + 3; + + host->wait_for = MMCIF_WAIT_FOR_READ; + schedule_delayed_work(&host->timeout_work, host->timeout); /* buf read enable */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; - for (i = 0; i < blocksize / 4; i++) +} + +static bool sh_mmcif_read_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = sg_virt(data->sg); + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; + } + + for (i = 0; i < host->blocksize / 4; i++) *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); /* buffer read end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); + host->wait_for = MMCIF_WAIT_FOR_READ_END; - return 0; + return true; } -static int sh_mmcif_multi_read(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static void sh_mmcif_multi_read(struct sh_mmcif_host *host, + struct mmc_request *mrq) { struct mmc_data *data = mrq->data; - long time; - u32 blocksize, i, j, sec, *p; - - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, - MMCIF_CE_BLOCK_SET); - for (j = 0; j < data->sg_len; j++) { - p = sg_virt(data->sg); - for (sec = 0; sec < data->sg->length / blocksize; sec++) { - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); - /* buf read enable */ - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - for (i = 0; i < blocksize / 4; i++) - *p++ = sh_mmcif_readl(host->addr, - MMCIF_CE_DATA); - } - if (j < data->sg_len - 1) - data->sg++; + + if (!data->sg_len || !data->sg->length) + return; + + host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK; + + host->wait_for = MMCIF_WAIT_FOR_MREAD; + host->sg_idx = 0; + host->sg_blkidx = 0; + host->pio_ptr = sg_virt(data->sg); + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); +} + +static bool sh_mmcif_mread_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = host->pio_ptr; + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; } - return 0; + + BUG_ON(!data->sg->length); + + for (i = 0; i < host->blocksize / 4; i++) + *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); + + if (!sh_mmcif_next_block(host, p)) + return false; + + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); + + return true; } -static int sh_mmcif_single_write(struct sh_mmcif_host *host, +static void sh_mmcif_single_write(struct sh_mmcif_host *host, struct mmc_request *mrq) { - struct mmc_data *data = mrq->data; - long time; - u32 blocksize, i, *p = sg_virt(data->sg); + host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK) + 3; - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); + host->wait_for = MMCIF_WAIT_FOR_WRITE; + schedule_delayed_work(&host->timeout_work, host->timeout); /* buf write enable */ - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - blocksize = (BLOCK_SIZE_MASK & - sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3; - for (i = 0; i < blocksize / 4; i++) + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); +} + +static bool sh_mmcif_write_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = sg_virt(data->sg); + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; + } + + for (i = 0; i < host->blocksize / 4; i++) sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); /* buffer write end */ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); + host->wait_for = MMCIF_WAIT_FOR_WRITE_END; - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); - - return 0; + return true; } -static int sh_mmcif_multi_write(struct sh_mmcif_host *host, - struct mmc_request *mrq) +static void sh_mmcif_multi_write(struct sh_mmcif_host *host, + struct mmc_request *mrq) { struct mmc_data *data = mrq->data; - long time; - u32 i, sec, j, blocksize, *p; - blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr, - MMCIF_CE_BLOCK_SET); + if (!data->sg_len || !data->sg->length) + return; - for (j = 0; j < data->sg_len; j++) { - p = sg_virt(data->sg); - for (sec = 0; sec < data->sg->length / blocksize; sec++) { - sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); - /* buf write enable*/ - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); + host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & + BLOCK_SIZE_MASK; - if (time <= 0 || host->sd_error) - return sh_mmcif_error_manage(host); + host->wait_for = MMCIF_WAIT_FOR_MWRITE; + host->sg_idx = 0; + host->sg_blkidx = 0; + host->pio_ptr = sg_virt(data->sg); + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); +} - for (i = 0; i < blocksize / 4; i++) - sh_mmcif_writel(host->addr, - MMCIF_CE_DATA, *p++); - } - if (j < data->sg_len - 1) - data->sg++; +static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host) +{ + struct mmc_data *data = host->mrq->data; + u32 *p = host->pio_ptr; + int i; + + if (host->sd_error) { + data->error = sh_mmcif_error_manage(host); + return false; } - return 0; + + BUG_ON(!data->sg->length); + + for (i = 0; i < host->blocksize / 4; i++) + sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); + + if (!sh_mmcif_next_block(host, p)) + return false; + + schedule_delayed_work(&host->timeout_work, host->timeout); + sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); + + return true; } static void sh_mmcif_get_response(struct sh_mmcif_host *host, @@ -603,8 +714,11 @@ static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, } static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq, struct mmc_command *cmd, u32 opc) + struct mmc_request *mrq) { + struct mmc_data *data = mrq->data; + struct mmc_command *cmd = mrq->cmd; + u32 opc = cmd->opcode; u32 tmp = 0; /* Response Type check */ @@ -636,7 +750,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, break; } /* WDAT / DATW */ - if (host->data) { + if (data) { tmp |= CMD_SET_WDAT; switch (host->bus_width) { case MMC_BUS_WIDTH_1: @@ -660,7 +774,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, - mrq->data->blocks << 16); + data->blocks << 16); } /* RIDXC[1:0] check bits */ if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || @@ -674,68 +788,60 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, opc == MMC_SEND_CSD || opc == MMC_SEND_CID) tmp |= CMD_SET_CRC7C_INTERNAL; - return opc = ((opc << 24) | tmp); + return (opc << 24) | tmp; } static int sh_mmcif_data_trans(struct sh_mmcif_host *host, - struct mmc_request *mrq, u32 opc) + struct mmc_request *mrq, u32 opc) { - int ret; - switch (opc) { case MMC_READ_MULTIPLE_BLOCK: - ret = sh_mmcif_multi_read(host, mrq); - break; + sh_mmcif_multi_read(host, mrq); + return 0; case MMC_WRITE_MULTIPLE_BLOCK: - ret = sh_mmcif_multi_write(host, mrq); - break; + sh_mmcif_multi_write(host, mrq); + return 0; case MMC_WRITE_BLOCK: - ret = sh_mmcif_single_write(host, mrq); - break; + sh_mmcif_single_write(host, mrq); + return 0; case MMC_READ_SINGLE_BLOCK: case MMC_SEND_EXT_CSD: - ret = sh_mmcif_single_read(host, mrq); - break; + sh_mmcif_single_read(host, mrq); + return 0; default: dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc); - ret = -EINVAL; - break; + return -EINVAL; } - return ret; } static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq, struct mmc_command *cmd) + struct mmc_request *mrq) { - long time; - int ret = 0, mask = 0; + struct mmc_command *cmd = mrq->cmd; u32 opc = cmd->opcode; + u32 mask; switch (opc) { - /* respons busy check */ + /* response busy check */ case MMC_SWITCH: case MMC_STOP_TRANSMISSION: case MMC_SET_WRITE_PROT: case MMC_CLR_WRITE_PROT: case MMC_ERASE: case MMC_GEN_CMD: - mask = MASK_MRBSYE; + mask = MASK_START_CMD | MASK_MRBSYE; break; default: - mask = MASK_MCRSPE; + mask = MASK_START_CMD | MASK_MCRSPE; break; } - mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | - MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | - MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | - MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; - if (host->data) { + if (mrq->data) { sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, mrq->data->blksz); } - opc = sh_mmcif_set_cmd(host, mrq, cmd, opc); + opc = sh_mmcif_set_cmd(host, mrq); sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); @@ -744,80 +850,28 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, /* set cmd */ sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0) { - cmd->error = sh_mmcif_error_manage(host); - return; - } - if (host->sd_error) { - switch (cmd->opcode) { - case MMC_ALL_SEND_CID: - case MMC_SELECT_CARD: - case MMC_APP_CMD: - cmd->error = -ETIMEDOUT; - break; - default: - dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n", - cmd->opcode); - cmd->error = sh_mmcif_error_manage(host); - break; - } - host->sd_error = false; - return; - } - if (!(cmd->flags & MMC_RSP_PRESENT)) { - cmd->error = 0; - return; - } - sh_mmcif_get_response(host, cmd); - if (host->data) { - if (!host->dma_active) { - ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); - } else { - long time = - wait_for_completion_interruptible_timeout(&host->dma_complete, - host->timeout); - if (!time) - ret = -ETIMEDOUT; - else if (time < 0) - ret = time; - sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, - BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - host->dma_active = false; - } - if (ret < 0) - mrq->data->bytes_xfered = 0; - else - mrq->data->bytes_xfered = - mrq->data->blocks * mrq->data->blksz; - } - cmd->error = ret; + host->wait_for = MMCIF_WAIT_FOR_CMD; + schedule_delayed_work(&host->timeout_work, host->timeout); } static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, - struct mmc_request *mrq, struct mmc_command *cmd) + struct mmc_request *mrq) { - long time; - - if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) + switch (mrq->cmd->opcode) { + case MMC_READ_MULTIPLE_BLOCK: sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); - else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) + break; + case MMC_WRITE_MULTIPLE_BLOCK: sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - else { + break; + default: dev_err(&host->pd->dev, "unsupported stop cmd\n"); - cmd->error = sh_mmcif_error_manage(host); + mrq->stop->error = sh_mmcif_error_manage(host); return; } - time = wait_for_completion_interruptible_timeout(&host->intr_wait, - host->timeout); - if (time <= 0 || host->sd_error) { - cmd->error = sh_mmcif_error_manage(host); - return; - } - sh_mmcif_get_cmd12response(host, cmd); - cmd->error = 0; + host->wait_for = MMCIF_WAIT_FOR_STOP; + schedule_delayed_work(&host->timeout_work, host->timeout); } static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) @@ -856,23 +910,10 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) default: break; } - host->data = mrq->data; - if (mrq->data) { - if (mrq->data->flags & MMC_DATA_READ) { - if (host->chan_rx) - sh_mmcif_start_dma_rx(host); - } else { - if (host->chan_tx) - sh_mmcif_start_dma_tx(host); - } - } - sh_mmcif_start_cmd(host, mrq, mrq->cmd); - host->data = NULL; - if (!mrq->cmd->error && mrq->stop) - sh_mmcif_stop_cmd(host, mrq, mrq->stop); - host->state = STATE_IDLE; - mmc_request_done(mmc, mrq); + host->mrq = mrq; + + sh_mmcif_start_cmd(host, mrq); } static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) @@ -947,9 +988,156 @@ static struct mmc_host_ops sh_mmcif_ops = { .get_cd = sh_mmcif_get_cd, }; -static void sh_mmcif_detect(struct mmc_host *mmc) +static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) { - mmc_detect_change(mmc, 0); + struct mmc_command *cmd = host->mrq->cmd; + struct mmc_data *data = host->mrq->data; + long time; + + if (host->sd_error) { + switch (cmd->opcode) { + case MMC_ALL_SEND_CID: + case MMC_SELECT_CARD: + case MMC_APP_CMD: + cmd->error = -ETIMEDOUT; + host->sd_error = false; + break; + default: + cmd->error = sh_mmcif_error_manage(host); + dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n", + cmd->opcode, cmd->error); + break; + } + return false; + } + if (!(cmd->flags & MMC_RSP_PRESENT)) { + cmd->error = 0; + return false; + } + + sh_mmcif_get_response(host, cmd); + + if (!data) + return false; + + if (data->flags & MMC_DATA_READ) { + if (host->chan_rx) + sh_mmcif_start_dma_rx(host); + } else { + if (host->chan_tx) + sh_mmcif_start_dma_tx(host); + } + + if (!host->dma_active) { + data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode); + if (!data->error) + return true; + return false; + } + + /* Running in the IRQ thread, can sleep */ + time = wait_for_completion_interruptible_timeout(&host->dma_complete, + host->timeout); + if (host->sd_error) { + dev_err(host->mmc->parent, + "Error IRQ while waiting for DMA completion!\n"); + /* Woken up by an error IRQ: abort DMA */ + if (data->flags & MMC_DATA_READ) + dmaengine_terminate_all(host->chan_rx); + else + dmaengine_terminate_all(host->chan_tx); + data->error = sh_mmcif_error_manage(host); + } else if (!time) { + data->error = -ETIMEDOUT; + } else if (time < 0) { + data->error = time; + } + sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, + BUF_ACC_DMAREN | BUF_ACC_DMAWEN); + host->dma_active = false; + + if (data->error) + data->bytes_xfered = 0; + + return false; +} + +static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) +{ + struct sh_mmcif_host *host = dev_id; + struct mmc_request *mrq = host->mrq; + struct mmc_data *data = mrq->data; + + cancel_delayed_work_sync(&host->timeout_work); + + /* + * All handlers return true, if processing continues, and false, if the + * request has to be completed - successfully or not + */ + switch (host->wait_for) { + case MMCIF_WAIT_FOR_REQUEST: + /* We're too late, the timeout has already kicked in */ + return IRQ_HANDLED; + case MMCIF_WAIT_FOR_CMD: + if (sh_mmcif_end_cmd(host)) + /* Wait for data */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_MREAD: + if (sh_mmcif_mread_block(host)) + /* Wait for more data */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_READ: + if (sh_mmcif_read_block(host)) + /* Wait for data end */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_MWRITE: + if (sh_mmcif_mwrite_block(host)) + /* Wait data to write */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_WRITE: + if (sh_mmcif_write_block(host)) + /* Wait for data end */ + return IRQ_HANDLED; + break; + case MMCIF_WAIT_FOR_STOP: + if (host->sd_error) { + mrq->stop->error = sh_mmcif_error_manage(host); + break; + } + sh_mmcif_get_cmd12response(host, mrq->stop); + mrq->stop->error = 0; + break; + case MMCIF_WAIT_FOR_READ_END: + case MMCIF_WAIT_FOR_WRITE_END: + if (host->sd_error) + data->error = sh_mmcif_error_manage(host); + break; + default: + BUG(); + } + + if (host->wait_for != MMCIF_WAIT_FOR_STOP) { + if (!mrq->cmd->error && data && !data->error) + data->bytes_xfered = + data->blocks * data->blksz; + + if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { + sh_mmcif_stop_cmd(host, mrq); + if (!mrq->stop->error) + return IRQ_HANDLED; + } + } + + host->wait_for = MMCIF_WAIT_FOR_REQUEST; + host->state = STATE_IDLE; + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); + + return IRQ_HANDLED; } static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) @@ -960,7 +1148,12 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); - if (state & INT_RBSYE) { + if (state & INT_ERR_STS) { + /* error interrupts - process first */ + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); + sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); + err = 1; + } else if (state & INT_RBSYE) { sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE); @@ -988,11 +1181,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(INT_CMD12RBE | INT_CMD12CRE)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); - } else if (state & INT_ERR_STS) { - /* err interrupts */ - sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); - sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state); - err = 1; } else { dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state); sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state); @@ -1003,14 +1191,57 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } - if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) - complete(&host->intr_wait); - else + if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { + if (!host->dma_active) + return IRQ_WAKE_THREAD; + else if (host->sd_error) + mmcif_dma_complete(host); + } else { dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state); + } return IRQ_HANDLED; } +static void mmcif_timeout_work(struct work_struct *work) +{ + struct delayed_work *d = container_of(work, struct delayed_work, work); + struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); + struct mmc_request *mrq = host->mrq; + + if (host->dying) + /* Don't run after mmc_remove_host() */ + return; + + /* + * Handle races with cancel_delayed_work(), unless + * cancel_delayed_work_sync() is used + */ + switch (host->wait_for) { + case MMCIF_WAIT_FOR_CMD: + mrq->cmd->error = sh_mmcif_error_manage(host); + break; + case MMCIF_WAIT_FOR_STOP: + mrq->stop->error = sh_mmcif_error_manage(host); + break; + case MMCIF_WAIT_FOR_MREAD: + case MMCIF_WAIT_FOR_MWRITE: + case MMCIF_WAIT_FOR_READ: + case MMCIF_WAIT_FOR_WRITE: + case MMCIF_WAIT_FOR_READ_END: + case MMCIF_WAIT_FOR_WRITE_END: + mrq->data->error = sh_mmcif_error_manage(host); + break; + default: + BUG(); + } + + host->state = STATE_IDLE; + host->wait_for = MMCIF_WAIT_FOR_REQUEST; + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); +} + static int __devinit sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; @@ -1064,7 +1295,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) host->clk = clk_get_rate(host->hclk); host->pd = pdev; - init_completion(&host->intr_wait); spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops; @@ -1101,19 +1331,21 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); - ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host); + ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host); if (ret) { dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n"); goto clean_up3; } - ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host); + ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host); if (ret) { free_irq(irq[0], host); dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n"); goto clean_up3; } - sh_mmcif_detect(host->mmc); + INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work); + + mmc_detect_change(host->mmc, 0); dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); dev_dbg(&pdev->dev, "chip ver H'%04x\n", @@ -1139,11 +1371,19 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev) struct sh_mmcif_host *host = platform_get_drvdata(pdev); int irq[2]; + host->dying = true; pm_runtime_get_sync(&pdev->dev); mmc_remove_host(host->mmc); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); + /* + * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the + * mmc_remove_host() call above. But swapping order doesn't help either + * (a query on the linux-mmc mailing list didn't bring any replies). + */ + cancel_delayed_work_sync(&host->timeout_work); + if (host->addr) iounmap(host->addr); @@ -1206,19 +1446,7 @@ static struct platform_driver sh_mmcif_driver = { }, }; -static int __init sh_mmcif_init(void) -{ - return platform_driver_register(&sh_mmcif_driver); -} - -static void __exit sh_mmcif_exit(void) -{ - platform_driver_unregister(&sh_mmcif_driver); -} - -module_init(sh_mmcif_init); -module_exit(sh_mmcif_exit); - +module_platform_driver(sh_mmcif_driver); MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 41ae6466bd83..58da3c44acc5 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -282,18 +282,7 @@ static struct platform_driver sh_mobile_sdhi_driver = { .remove = __devexit_p(sh_mobile_sdhi_remove), }; -static int __init sh_mobile_sdhi_init(void) -{ - return platform_driver_register(&sh_mobile_sdhi_driver); -} - -static void __exit sh_mobile_sdhi_exit(void) -{ - platform_driver_unregister(&sh_mobile_sdhi_driver); -} - -module_init(sh_mobile_sdhi_init); -module_exit(sh_mobile_sdhi_exit); +module_platform_driver(sh_mobile_sdhi_driver); MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); MODULE_AUTHOR("Magnus Damm"); diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index f70d04664cac..43d962829f8e 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -22,8 +22,8 @@ #define DRIVER_NAME "tifm_sd" #define DRIVER_VERSION "0.8" -static int no_dma = 0; -static int fixed_timeout = 0; +static bool no_dma = 0; +static bool fixed_timeout = 0; module_param(no_dma, bool, 0644); module_param(fixed_timeout, bool, 0644); @@ -118,7 +118,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off; + buf = kmap_atomic(pg) + off; if (host->cmd_flags & DATA_CARRY) { buf[pos++] = host->bounce_buf_data[0]; host->cmd_flags &= ~DATA_CARRY; @@ -134,7 +134,7 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, } buf[pos++] = (val >> 8) & 0xff; } - kunmap_atomic(buf - off, KM_BIO_DST_IRQ); + kunmap_atomic(buf - off); } static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, @@ -144,7 +144,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off; + buf = kmap_atomic(pg) + off; if (host->cmd_flags & DATA_CARRY) { val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); writel(val, sock->addr + SOCK_MMCSD_DATA); @@ -161,7 +161,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, val |= (buf[pos++] << 8) & 0xff00; writel(val, sock->addr + SOCK_MMCSD_DATA); } - kunmap_atomic(buf - off, KM_BIO_SRC_IRQ); + kunmap_atomic(buf - off); } static void tifm_sd_transfer_data(struct tifm_sd *host) @@ -212,13 +212,13 @@ static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, struct page *src, unsigned int src_off, unsigned int count) { - unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off; - unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off; + unsigned char *src_buf = kmap_atomic(src) + src_off; + unsigned char *dst_buf = kmap_atomic(dst) + dst_off; memcpy(dst_buf, src_buf, count); - kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ); - kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ); + kunmap_atomic(dst_buf - dst_off); + kunmap_atomic(src_buf - src_off); } static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index a4ea10242787..113ce6c9cf32 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -138,19 +138,7 @@ static struct platform_driver tmio_mmc_driver = { .resume = tmio_mmc_resume, }; - -static int __init tmio_mmc_init(void) -{ - return platform_driver_register(&tmio_mmc_driver); -} - -static void __exit tmio_mmc_exit(void) -{ - platform_driver_unregister(&tmio_mmc_driver); -} - -module_init(tmio_mmc_init); -module_exit(tmio_mmc_exit); +module_platform_driver(tmio_mmc_driver); MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver"); MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 3020f98218f0..a95e6d901726 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -105,13 +105,13 @@ static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; + return kmap_atomic(sg_page(sg)) + sg->offset; } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) { - kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); + kunmap_atomic(virt - sg->offset); local_irq_restore(*flags); } diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 4208b3958069..abad01b37cfb 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -800,8 +800,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } else if (ios->power_mode != MMC_POWER_UP) { if (host->set_pwr && ios->power_mode == MMC_POWER_OFF) host->set_pwr(host->pdev, 0); - if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && - pdata->power) { + if (pdata->power) { pdata->power = false; pm_runtime_put(&host->pdev->dev); } @@ -915,6 +914,23 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, if (ret < 0) goto pm_disable; + /* + * There are 4 different scenarios for the card detection: + * 1) an external gpio irq handles the cd (best for power savings) + * 2) internal sdhi irq handles the cd + * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL + * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE + * + * While we increment the rtpm counter for all scenarios when the mmc + * core activates us by calling an appropriate set_ios(), we must + * additionally ensure that in case 2) the tmio mmc hardware stays + * powered on during runtime for the card detection to work. + */ + if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD + || mmc->caps & MMC_CAP_NEEDS_POLL + || mmc->caps & MMC_CAP_NONREMOVABLE)) + pm_runtime_get_noresume(&pdev->dev); + tmio_mmc_clk_stop(_host); tmio_mmc_reset(_host); @@ -933,12 +949,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, /* See if we also get DMA */ tmio_mmc_request_dma(_host, pdata); - /* We have to keep the device powered for its card detection to work */ - if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) { - pdata->power = true; - pm_runtime_get_noresume(&pdev->dev); - } - mmc_add_host(mmc); /* Unmask the IRQs we want to know about */ @@ -974,7 +984,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) * the controller, the runtime PM is suspended and pdata->power == false, * so, our .runtime_resume() will not try to detect a card in the slot. */ - if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD) + if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD + || host->mmc->caps & MMC_CAP_NEEDS_POLL + || host->mmc->caps & MMC_CAP_NONREMOVABLE) pm_runtime_get_sync(&pdev->dev); mmc_remove_host(host->mmc); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 2ec978bc32ba..3135a1a5d75d 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -223,25 +223,25 @@ enum SD_RESPONSE_TYPE { #define FUN(c) (0x000007 & (c->arg>>28)) #define REG(c) (0x01FFFF & (c->arg>>9)) -static int limit_speed_to_24_MHz; +static bool limit_speed_to_24_MHz; module_param(limit_speed_to_24_MHz, bool, 0644); MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz"); -static int pad_input_to_usb_pkt; +static bool pad_input_to_usb_pkt; module_param(pad_input_to_usb_pkt, bool, 0644); MODULE_PARM_DESC(pad_input_to_usb_pkt, "Pad USB data input transfers to whole USB Packet"); -static int disable_offload_processing; +static bool disable_offload_processing; module_param(disable_offload_processing, bool, 0644); MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing"); -static int force_1_bit_data_xfers; +static bool force_1_bit_data_xfers; module_param(force_1_bit_data_xfers, bool, 0644); MODULE_PARM_DESC(force_1_bit_data_xfers, "Force SDIO Data Transfers to 1-bit Mode"); -static int force_polling_for_irqs; +static bool force_polling_for_irqs; module_param(force_polling_for_irqs, bool, 0644); MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts"); diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index db8e8272d69b..3ce99e00a49e 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -315,8 +315,7 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper, char *dst; if (reason != KMSG_DUMP_OOPS && - reason != KMSG_DUMP_PANIC && - reason != KMSG_DUMP_KEXEC) + reason != KMSG_DUMP_PANIC) return; /* Only dump oopses if dump_oops is set */ diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 7dd3700f2303..73abbc3e093e 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -17,35 +17,19 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/partitions.h> +#include <linux/platform_device.h> #include <asm/io.h> +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1550nd.h> -#ifdef CONFIG_MIPS_PB1550 -#include <asm/mach-pb1x00/pb1550.h> -#elif defined(CONFIG_MIPS_DB1550) -#include <asm/mach-db1x00/db1x00.h> -#endif -#include <asm/mach-db1x00/bcsr.h> -/* - * MTD structure for NAND controller - */ -static struct mtd_info *au1550_mtd = NULL; -static void __iomem *p_nand; -static int nand_width = 1; /* default x8 */ -static void (*au1550_write_byte)(struct mtd_info *, u_char); +struct au1550nd_ctx { + struct mtd_info info; + struct nand_chip chip; -/* - * Define partitions for flash device - */ -static const struct mtd_partition partition_info[] = { - { - .name = "NAND FS 0", - .offset = 0, - .size = 8 * 1024 * 1024}, - { - .name = "NAND FS 1", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL} + int cs; + void __iomem *base; + void (*write_byte)(struct mtd_info *, u_char); }; /** @@ -259,24 +243,25 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) { - register struct nand_chip *this = mtd->priv; + struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info); + struct nand_chip *this = mtd->priv; switch (cmd) { case NAND_CTL_SETCLE: - this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; + this->IO_ADDR_W = ctx->base + MEM_STNAND_CMD; break; case NAND_CTL_CLRCLE: - this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA; break; case NAND_CTL_SETALE: - this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; + this->IO_ADDR_W = ctx->base + MEM_STNAND_ADDR; break; case NAND_CTL_CLRALE: - this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + this->IO_ADDR_W = ctx->base + MEM_STNAND_DATA; /* FIXME: Nobody knows why this is necessary, * but it works only that way */ udelay(1); @@ -284,7 +269,7 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) case NAND_CTL_SETNCE: /* assert (force assert) chip enable */ - au_writel((1 << (4 + NAND_CS)), MEM_STNDCTL); + au_writel((1 << (4 + ctx->cs)), MEM_STNDCTL); break; case NAND_CTL_CLRNCE: @@ -331,9 +316,10 @@ static void au1550_select_chip(struct mtd_info *mtd, int chip) */ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) { - register struct nand_chip *this = mtd->priv; + struct au1550nd_ctx *ctx = container_of(mtd, struct au1550nd_ctx, info); + struct nand_chip *this = mtd->priv; int ce_override = 0, i; - ulong flags; + unsigned long flags = 0; /* Begin command latch cycle */ au1550_hwcontrol(mtd, NAND_CTL_SETCLE); @@ -354,9 +340,9 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i column -= 256; readcmd = NAND_CMD_READ1; } - au1550_write_byte(mtd, readcmd); + ctx->write_byte(mtd, readcmd); } - au1550_write_byte(mtd, command); + ctx->write_byte(mtd, command); /* Set ALE and clear CLE to start address cycle */ au1550_hwcontrol(mtd, NAND_CTL_CLRCLE); @@ -369,10 +355,10 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i /* Adjust columns for 16 bit buswidth */ if (this->options & NAND_BUSWIDTH_16) column >>= 1; - au1550_write_byte(mtd, column); + ctx->write_byte(mtd, column); } if (page_addr != -1) { - au1550_write_byte(mtd, (u8)(page_addr & 0xff)); + ctx->write_byte(mtd, (u8)(page_addr & 0xff)); if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || @@ -390,11 +376,12 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i au1550_hwcontrol(mtd, NAND_CTL_SETNCE); } - au1550_write_byte(mtd, (u8)(page_addr >> 8)); + ctx->write_byte(mtd, (u8)(page_addr >> 8)); /* One more address cycle for devices > 32MiB */ if (this->chipsize > (32 << 20)) - au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); + ctx->write_byte(mtd, + ((page_addr >> 16) & 0x0f)); } /* Latch in address */ au1550_hwcontrol(mtd, NAND_CTL_CLRALE); @@ -440,121 +427,79 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i while(!this->dev_ready(mtd)); } - -/* - * Main initialization routine - */ -static int __init au1xxx_nand_init(void) +static int __devinit find_nand_cs(unsigned long nand_base) { - struct nand_chip *this; - u16 boot_swapboot = 0; /* default value */ - int retval; - u32 mem_staddr; - u32 nand_phys; - - /* Allocate memory for MTD device structure and private data */ - au1550_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!au1550_mtd) { - printk("Unable to allocate NAND MTD dev structure.\n"); - return -ENOMEM; - } - - /* Get pointer to private data */ - this = (struct nand_chip *)(&au1550_mtd[1]); - - /* Link the private data with the MTD structure */ - au1550_mtd->priv = this; - au1550_mtd->owner = THIS_MODULE; - + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR); + unsigned long addr, staddr, start, mask, end; + int i; - /* MEM_STNDCTL: disable ints, disable nand boot */ - au_writel(0, MEM_STNDCTL); + for (i = 0; i < 4; i++) { + addr = 0x1000 + (i * 0x10); /* CSx */ + staddr = __raw_readl(base + addr + 0x08); /* STADDRx */ + /* figure out the decoded range of this CS */ + start = (staddr << 4) & 0xfffc0000; + mask = (staddr << 18) & 0xfffc0000; + end = (start | (start - 1)) & ~(start ^ mask); + if ((nand_base >= start) && (nand_base < end)) + return i; + } -#ifdef CONFIG_MIPS_PB1550 - /* set gpio206 high */ - gpio_direction_input(206); + return -ENODEV; +} - boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1); +static int __devinit au1550nd_probe(struct platform_device *pdev) +{ + struct au1550nd_platdata *pd; + struct au1550nd_ctx *ctx; + struct nand_chip *this; + struct resource *r; + int ret, cs; - switch (boot_swapboot) { - case 0: - case 2: - case 8: - case 0xC: - case 0xD: - /* x16 NAND Flash */ - nand_width = 0; - break; - case 1: - case 9: - case 3: - case 0xE: - case 0xF: - /* x8 NAND Flash */ - nand_width = 1; - break; - default: - printk("Pb1550 NAND: bad boot:swap\n"); - retval = -EINVAL; - goto outmem; + pd = pdev->dev.platform_data; + if (!pd) { + dev_err(&pdev->dev, "missing platform data\n"); + return -ENODEV; } -#endif - - /* Configure chip-select; normally done by boot code, e.g. YAMON */ -#ifdef NAND_STCFG - if (NAND_CS == 0) { - au_writel(NAND_STCFG, MEM_STCFG0); - au_writel(NAND_STTIME, MEM_STTIME0); - au_writel(NAND_STADDR, MEM_STADDR0); - } - if (NAND_CS == 1) { - au_writel(NAND_STCFG, MEM_STCFG1); - au_writel(NAND_STTIME, MEM_STTIME1); - au_writel(NAND_STADDR, MEM_STADDR1); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + dev_err(&pdev->dev, "no memory for NAND context\n"); + return -ENOMEM; } - if (NAND_CS == 2) { - au_writel(NAND_STCFG, MEM_STCFG2); - au_writel(NAND_STTIME, MEM_STTIME2); - au_writel(NAND_STADDR, MEM_STADDR2); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no NAND memory resource\n"); + ret = -ENODEV; + goto out1; } - if (NAND_CS == 3) { - au_writel(NAND_STCFG, MEM_STCFG3); - au_writel(NAND_STTIME, MEM_STTIME3); - au_writel(NAND_STADDR, MEM_STADDR3); + if (request_mem_region(r->start, resource_size(r), "au1550-nand")) { + dev_err(&pdev->dev, "cannot claim NAND memory area\n"); + ret = -ENOMEM; + goto out1; } -#endif - - /* Locate NAND chip-select in order to determine NAND phys address */ - mem_staddr = 0x00000000; - if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0)) - mem_staddr = au_readl(MEM_STADDR0); - else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1)) - mem_staddr = au_readl(MEM_STADDR1); - else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2)) - mem_staddr = au_readl(MEM_STADDR2); - else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3)) - mem_staddr = au_readl(MEM_STADDR3); - - if (mem_staddr == 0x00000000) { - printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n"); - kfree(au1550_mtd); - return 1; + + ctx->base = ioremap_nocache(r->start, 0x1000); + if (!ctx->base) { + dev_err(&pdev->dev, "cannot remap NAND memory area\n"); + ret = -ENODEV; + goto out2; } - nand_phys = (mem_staddr << 4) & 0xFFFC0000; - p_nand = ioremap(nand_phys, 0x1000); + this = &ctx->chip; + ctx->info.priv = this; + ctx->info.owner = THIS_MODULE; - /* make controller and MTD agree */ - if (NAND_CS == 0) - nand_width = au_readl(MEM_STCFG0) & (1 << 22); - if (NAND_CS == 1) - nand_width = au_readl(MEM_STCFG1) & (1 << 22); - if (NAND_CS == 2) - nand_width = au_readl(MEM_STCFG2) & (1 << 22); - if (NAND_CS == 3) - nand_width = au_readl(MEM_STCFG3) & (1 << 22); + /* figure out which CS# r->start belongs to */ + cs = find_nand_cs(r->start); + if (cs < 0) { + dev_err(&pdev->dev, "cannot detect NAND chipselect\n"); + ret = -ENODEV; + goto out3; + } + ctx->cs = cs; - /* Set address of hardware control function */ this->dev_ready = au1550_device_ready; this->select_chip = au1550_select_chip; this->cmdfunc = au1550_command; @@ -565,54 +510,57 @@ static int __init au1xxx_nand_init(void) this->options = NAND_NO_AUTOINCR; - if (!nand_width) + if (pd->devwidth) this->options |= NAND_BUSWIDTH_16; - this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; - au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; + this->read_byte = (pd->devwidth) ? au_read_byte16 : au_read_byte; + ctx->write_byte = (pd->devwidth) ? au_write_byte16 : au_write_byte; this->read_word = au_read_word; - this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; - this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; - this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf; - - /* Scan to find existence of the device */ - if (nand_scan(au1550_mtd, 1)) { - retval = -ENXIO; - goto outio; + this->write_buf = (pd->devwidth) ? au_write_buf16 : au_write_buf; + this->read_buf = (pd->devwidth) ? au_read_buf16 : au_read_buf; + this->verify_buf = (pd->devwidth) ? au_verify_buf16 : au_verify_buf; + + ret = nand_scan(&ctx->info, 1); + if (ret) { + dev_err(&pdev->dev, "NAND scan failed with %d\n", ret); + goto out3; } - /* Register the partitions */ - mtd_device_register(au1550_mtd, partition_info, - ARRAY_SIZE(partition_info)); + mtd_device_register(&ctx->info, pd->parts, pd->num_parts); return 0; - outio: - iounmap(p_nand); - - outmem: - kfree(au1550_mtd); - return retval; +out3: + iounmap(ctx->base); +out2: + release_mem_region(r->start, resource_size(r)); +out1: + kfree(ctx); + return ret; } -module_init(au1xxx_nand_init); - -/* - * Clean up routine - */ -static void __exit au1550_cleanup(void) +static int __devexit au1550nd_remove(struct platform_device *pdev) { - /* Release resources, unregister device */ - nand_release(au1550_mtd); + struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); + struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - /* Free the MTD device structure */ - kfree(au1550_mtd); - - /* Unmap */ - iounmap(p_nand); + nand_release(&ctx->info); + iounmap(ctx->base); + release_mem_region(r->start, 0x1000); + kfree(ctx); + return 0; } -module_exit(au1550_cleanup); +static struct platform_driver au1550nd_driver = { + .driver = { + .name = "au1550-nand", + .owner = THIS_MODULE, + }, + .probe = au1550nd_probe, + .remove = __devexit_p(au1550nd_remove), +}; + +module_platform_driver(au1550nd_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Embedded Edge, LLC"); diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 8544d6bf50a0..5c3d719c37e6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -185,7 +185,7 @@ struct pxa3xx_nand_info { uint32_t ndcb2; }; -static int use_dma = 1; +static bool use_dma = 1; module_param(use_dma, bool, 0444); MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW"); diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index f20f393bfda6..769a4e096b3c 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -22,7 +22,7 @@ #include "r852.h" -static int r852_enable_dma = 1; +static bool r852_enable_dma = 1; module_param(r852_enable_dma, bool, S_IRUGO); MODULE_PARM_DESC(r852_enable_dma, "Enable usage of the DMA (default)"); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 3320a50ba4f0..ad76592fb2f4 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -632,6 +632,9 @@ static int verify_mkvol_req(const struct ubi_device *ubi, if (req->alignment != 1 && n) goto bad; + if (!req->name[0] || !req->name_len) + goto bad; + if (req->name_len > UBI_VOL_NAME_MAX) { err = -ENAMETOOLONG; goto bad; diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 64fbb0021825..ead2cd16ba75 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -43,7 +43,10 @@ pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__) /* Just a debugging messages not related to any specific UBI subsystem */ -#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__) +#define dbg_msg(fmt, ...) \ + printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ + current->pid, __func__, ##__VA_ARGS__) + /* General debugging messages */ #define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__) /* Messages from the eraseblock association sub-system */ diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 9ad18da1891d..17cec0c01544 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -306,7 +306,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, int copy, void *vtbl) { int err, tries = 0; - static struct ubi_vid_hdr *vid_hdr; + struct ubi_vid_hdr *vid_hdr; struct ubi_scan_leb *new_seb; ubi_msg("create volume table (copy #%d)", copy + 1); @@ -322,7 +322,7 @@ retry: goto out_free; } - vid_hdr->vol_type = UBI_VID_DYNAMIC; + vid_hdr->vol_type = UBI_LAYOUT_VOLUME_TYPE; vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; vid_hdr->data_size = vid_hdr->used_ebs = @@ -632,7 +632,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, return -ENOMEM; vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS; - vol->alignment = 1; + vol->alignment = UBI_LAYOUT_VOLUME_ALIGN; vol->vol_type = UBI_DYNAMIC_VOLUME; vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1; memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 106b88a04738..342626f4bc46 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -99,16 +99,26 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size) /*********************** tlb specific functions ***************************/ -static inline void _lock_tx_hashtbl(struct bonding *bond) +static inline void _lock_tx_hashtbl_bh(struct bonding *bond) { spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } -static inline void _unlock_tx_hashtbl(struct bonding *bond) +static inline void _unlock_tx_hashtbl_bh(struct bonding *bond) { spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); } +static inline void _lock_tx_hashtbl(struct bonding *bond) +{ + spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); +} + +static inline void _unlock_tx_hashtbl(struct bonding *bond) +{ + spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock)); +} + /* Caller must hold tx_hashtbl lock */ static inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load) { @@ -129,14 +139,13 @@ static inline void tlb_init_slave(struct slave *slave) SLAVE_TLB_INFO(slave).head = TLB_NULL_INDEX; } -/* Caller must hold bond lock for read */ -static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_load) +/* Caller must hold bond lock for read, BH disabled */ +static void __tlb_clear_slave(struct bonding *bond, struct slave *slave, + int save_load) { struct tlb_client_info *tx_hash_table; u32 index; - _lock_tx_hashtbl(bond); - /* clear slave from tx_hashtbl */ tx_hash_table = BOND_ALB_INFO(bond).tx_hashtbl; @@ -151,8 +160,15 @@ static void tlb_clear_slave(struct bonding *bond, struct slave *slave, int save_ } tlb_init_slave(slave); +} - _unlock_tx_hashtbl(bond); +/* Caller must hold bond lock for read */ +static void tlb_clear_slave(struct bonding *bond, struct slave *slave, + int save_load) +{ + _lock_tx_hashtbl_bh(bond); + __tlb_clear_slave(bond, slave, save_load); + _unlock_tx_hashtbl_bh(bond); } /* Must be called before starting the monitor timer */ @@ -169,7 +185,7 @@ static int tlb_initialize(struct bonding *bond) bond->dev->name); return -1; } - _lock_tx_hashtbl(bond); + _lock_tx_hashtbl_bh(bond); bond_info->tx_hashtbl = new_hashtbl; @@ -177,7 +193,7 @@ static int tlb_initialize(struct bonding *bond) tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0); } - _unlock_tx_hashtbl(bond); + _unlock_tx_hashtbl_bh(bond); return 0; } @@ -187,12 +203,12 @@ static void tlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - _lock_tx_hashtbl(bond); + _lock_tx_hashtbl_bh(bond); kfree(bond_info->tx_hashtbl); bond_info->tx_hashtbl = NULL; - _unlock_tx_hashtbl(bond); + _unlock_tx_hashtbl_bh(bond); } static long long compute_gap(struct slave *slave) @@ -226,15 +242,13 @@ static struct slave *tlb_get_least_loaded_slave(struct bonding *bond) return least_loaded; } -/* Caller must hold bond lock for read */ -static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u32 skb_len) +static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index, + u32 skb_len) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct tlb_client_info *hash_table; struct slave *assigned_slave; - _lock_tx_hashtbl(bond); - hash_table = bond_info->tx_hashtbl; assigned_slave = hash_table[hash_index].tx_slave; if (!assigned_slave) { @@ -263,22 +277,46 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3 hash_table[hash_index].tx_bytes += skb_len; } - _unlock_tx_hashtbl(bond); - return assigned_slave; } +/* Caller must hold bond lock for read */ +static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, + u32 skb_len) +{ + struct slave *tx_slave; + /* + * We don't need to disable softirq here, becase + * tlb_choose_channel() is only called by bond_alb_xmit() + * which already has softirq disabled. + */ + _lock_tx_hashtbl(bond); + tx_slave = __tlb_choose_channel(bond, hash_index, skb_len); + _unlock_tx_hashtbl(bond); + return tx_slave; +} + /*********************** rlb specific functions ***************************/ -static inline void _lock_rx_hashtbl(struct bonding *bond) +static inline void _lock_rx_hashtbl_bh(struct bonding *bond) { spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } -static inline void _unlock_rx_hashtbl(struct bonding *bond) +static inline void _unlock_rx_hashtbl_bh(struct bonding *bond) { spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); } +static inline void _lock_rx_hashtbl(struct bonding *bond) +{ + spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); +} + +static inline void _unlock_rx_hashtbl(struct bonding *bond) +{ + spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock)); +} + /* when an ARP REPLY is received from a client update its info * in the rx_hashtbl */ @@ -288,7 +326,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) struct rlb_client_info *client_info; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); @@ -303,7 +341,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) bond_info->rx_ntt = 1; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond, @@ -401,7 +439,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) u32 index, next_index; /* clear slave from rx_hashtbl */ - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); rx_hash_table = bond_info->rx_hashtbl; index = bond_info->rx_hashtbl_head; @@ -432,7 +470,7 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) } } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); write_lock_bh(&bond->curr_slave_lock); @@ -489,7 +527,7 @@ static void rlb_update_rx_clients(struct bonding *bond) struct rlb_client_info *client_info; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { @@ -507,7 +545,7 @@ static void rlb_update_rx_clients(struct bonding *bond) */ bond_info->rlb_update_delay_counter = RLB_UPDATE_DELAY; - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /* The slave was assigned a new mac address - update the clients */ @@ -518,7 +556,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla int ntt = 0; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); hash_index = bond_info->rx_hashtbl_head; for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) { @@ -538,7 +576,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /* mark all clients using src_ip to be updated */ @@ -709,7 +747,7 @@ static void rlb_rebalance(struct bonding *bond) int ntt; u32 hash_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); ntt = 0; hash_index = bond_info->rx_hashtbl_head; @@ -727,7 +765,7 @@ static void rlb_rebalance(struct bonding *bond) if (ntt) { bond_info->rx_ntt = 1; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /* Caller must hold rx_hashtbl lock */ @@ -751,7 +789,7 @@ static int rlb_initialize(struct bonding *bond) bond->dev->name); return -1; } - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); bond_info->rx_hashtbl = new_hashtbl; @@ -761,7 +799,7 @@ static int rlb_initialize(struct bonding *bond) rlb_init_table_entry(bond_info->rx_hashtbl + i); } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); /* register to receive ARPs */ bond->recv_probe = rlb_arp_recv; @@ -773,13 +811,13 @@ static void rlb_deinitialize(struct bonding *bond) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); kfree(bond_info->rx_hashtbl); bond_info->rx_hashtbl = NULL; bond_info->rx_hashtbl_head = RLB_NULL_INDEX; - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) @@ -787,7 +825,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); u32 curr_index; - _lock_rx_hashtbl(bond); + _lock_rx_hashtbl_bh(bond); curr_index = bond_info->rx_hashtbl_head; while (curr_index != RLB_NULL_INDEX) { @@ -812,7 +850,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id) curr_index = next_index; } - _unlock_rx_hashtbl(bond); + _unlock_rx_hashtbl_bh(bond); } /*********************** tlb/rlb shared functions *********************/ @@ -1320,7 +1358,9 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) res = bond_dev_queue_xmit(bond, skb, tx_slave->dev); } else { if (tx_slave) { - tlb_clear_slave(bond, tx_slave, 0); + _lock_tx_hashtbl(bond); + __tlb_clear_slave(bond, tx_slave, 0); + _unlock_tx_hashtbl(bond); } } diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 9e8ba4f5636b..0f92e3567f68 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -623,7 +623,8 @@ static int ax_mii_init(struct net_device *dev) ax->mii_bus->name = "ax88796_mii_bus"; ax->mii_bus->parent = dev->dev.parent; - snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); + snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); ax->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!ax->mii_bus->irq) { diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c index b6d69c91db96..d812a103e032 100644 --- a/drivers/net/ethernet/adi/bfin_mac.c +++ b/drivers/net/ethernet/adi/bfin_mac.c @@ -1670,7 +1670,8 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev) miibus->name = "bfin_mii_bus"; miibus->phy_mask = mii_bus_pd->phy_mask; - snprintf(miibus->id, MII_BUS_ID_SIZE, "0"); + snprintf(miibus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); if (!miibus->irq) goto out_err_irq_alloc; diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c index cc9262be69c8..8b95dd314253 100644 --- a/drivers/net/ethernet/amd/au1000_eth.c +++ b/drivers/net/ethernet/amd/au1000_eth.c @@ -1171,7 +1171,8 @@ static int __devinit au1000_probe(struct platform_device *pdev) aup->mii_bus->write = au1000_mdiobus_write; aup->mii_bus->reset = au1000_mdiobus_reset; aup->mii_bus->name = "au1000_eth_mii"; - snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id); + snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, aup->mac_id); aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); if (aup->mii_bus->irq == NULL) goto err_out; diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index d44331eb07fe..986019b2c849 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1727,7 +1727,7 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev) bus->priv = priv; bus->read = bcm_enet_mdio_read_phylib; bus->write = bcm_enet_mdio_write_phylib; - sprintf(bus->id, "%d", priv->mac_id); + sprintf(bus->id, "%s-%d", pdev->name, priv->mac_id); /* only probe bus where we think the PHY is, because * the mdio read operation return 0 instead of 0xffff diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index 8fa7abc53ec6..084904ceaa30 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -2259,7 +2259,8 @@ static int sbmac_init(struct platform_device *pldev, long long base) } sc->mii_bus->name = sbmac_mdio_string; - snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); + snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pldev->name, idx); sc->mii_bus->priv = sc; sc->mii_bus->read = sbmac_mii_read; sc->mii_bus->write = sbmac_mii_write; diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index f3d5c65d99cf..23200680d4c1 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -243,7 +243,8 @@ static int macb_mii_init(struct macb *bp) bp->mii_bus->read = &macb_mdio_read; bp->mii_bus->write = &macb_mdio_write; bp->mii_bus->reset = &macb_mdio_reset; - snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + bp->pdev->name, bp->pdev->id); bp->mii_bus->priv = bp; bp->mii_bus->parent = &bp->dev->dev; pdata = bp->pdev->dev.platform_data; diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index ce88c0f399f6..925c9bafc9b9 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -325,7 +325,8 @@ static int dnet_mii_init(struct dnet *bp) bp->mii_bus->write = &dnet_mdio_write; bp->mii_bus->reset = &dnet_mdio_reset; - snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + bp->pdev->name, bp->pdev->id); bp->mii_bus->priv = bp; diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index ddcbbb34d1b9..7b25e9cf13f6 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -476,6 +476,7 @@ fec_restart(struct net_device *ndev, int duplex) } else { #ifdef FEC_MIIGSK_ENR if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) { + u32 cfgr; /* disable the gasket and wait */ writel(0, fep->hwp + FEC_MIIGSK_ENR); while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) @@ -486,9 +487,11 @@ fec_restart(struct net_device *ndev, int duplex) * RMII, 50 MHz, no loopback, no echo * MII, 25 MHz, no loopback, no echo */ - writel((fep->phy_interface == PHY_INTERFACE_MODE_RMII) ? - 1 : 0, fep->hwp + FEC_MIIGSK_CFGR); - + cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII) + ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII; + if (fep->phy_dev && fep->phy_dev->speed == SPEED_10) + cfgr |= BM_MIIGSK_CFGR_FRCONT_10M; + writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR); /* re-enable the gasket */ writel(2, fep->hwp + FEC_MIIGSK_ENR); @@ -1077,7 +1080,8 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->read = fec_enet_mdio_read; fep->mii_bus->write = fec_enet_mdio_write; fep->mii_bus->reset = fec_enet_mdio_reset; - snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->dev_id + 1); + snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, fep->dev_id + 1); fep->mii_bus->priv = fep; fep->mii_bus->parent = &pdev->dev; diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 8b2c6d797e6d..8408c627b195 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -47,6 +47,10 @@ #define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ #define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ +#define BM_MIIGSK_CFGR_MII 0x00 +#define BM_MIIGSK_CFGR_RMII 0x01 +#define BM_MIIGSK_CFGR_FRCONT_10M 0x40 + #else #define FEC_ECNTRL 0x000 /* Ethernet control reg */ diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index e01cdaa722a9..39d160d353a4 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1984,7 +1984,8 @@ static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) return fcb; } -static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb) +static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb, + int fcb_length) { u8 flags = 0; @@ -2006,7 +2007,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb) * frame (skb->data) and the start of the IP hdr. * l4os is the distance between the start of the * l3 hdr and the l4 hdr */ - fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN); + fcb->l3os = (u16)(skb_network_offset(skb) - fcb_length); fcb->l4os = skb_network_header_len(skb); fcb->flags = flags; @@ -2046,7 +2047,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) int i, rq = 0, do_tstamp = 0; u32 bufaddr; unsigned long flags; - unsigned int nr_frags, nr_txbds, length; + unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN; /* * TOE=1 frames larger than 2500 bytes may see excess delays @@ -2070,22 +2071,28 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* check if time stamp should be generated */ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && - priv->hwts_tx_en)) + priv->hwts_tx_en)) { do_tstamp = 1; + fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN; + } /* make space for additional header when fcb is needed */ if (((skb->ip_summed == CHECKSUM_PARTIAL) || vlan_tx_tag_present(skb) || unlikely(do_tstamp)) && - (skb_headroom(skb) < GMAC_FCB_LEN)) { + (skb_headroom(skb) < fcb_length)) { struct sk_buff *skb_new; - skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN); + skb_new = skb_realloc_headroom(skb, fcb_length); if (!skb_new) { dev->stats.tx_errors++; kfree_skb(skb); return NETDEV_TX_OK; } + + /* Steal sock reference for processing TX time stamps */ + swap(skb_new->sk, skb->sk); + swap(skb_new->destructor, skb->destructor); kfree_skb(skb); skb = skb_new; } @@ -2154,6 +2161,12 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) lstatus = txbdp_start->lstatus; } + /* Add TxPAL between FCB and frame if required */ + if (unlikely(do_tstamp)) { + skb_push(skb, GMAC_TXPAL_LEN); + memset(skb->data, 0, GMAC_TXPAL_LEN); + } + /* Set up checksumming */ if (CHECKSUM_PARTIAL == skb->ip_summed) { fcb = gfar_add_fcb(skb); @@ -2164,7 +2177,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_checksum_help(skb); } else { lstatus |= BD_LFLAG(TXBD_TOE); - gfar_tx_checksum(skb, fcb); + gfar_tx_checksum(skb, fcb, fcb_length); } } @@ -2196,9 +2209,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) * the full frame length. */ if (unlikely(do_tstamp)) { - txbdp_tstamp->bufPtr = txbdp_start->bufPtr + GMAC_FCB_LEN; + txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length; txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) | - (skb_headlen(skb) - GMAC_FCB_LEN); + (skb_headlen(skb) - fcb_length); lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN; } else { lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); @@ -2490,7 +2503,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { next = next_txbd(bdp, base, tx_ring_size); - buflen = next->length + GMAC_FCB_LEN; + buflen = next->length + GMAC_FCB_LEN + GMAC_TXPAL_LEN; } else buflen = bdp->length; @@ -2502,6 +2515,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7); memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ns_to_ktime(*ns); + skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN); skb_tstamp_tx(skb, &shhwtstamps); bdp->lstatus &= BD_LFLAG(TXBD_WRAP); bdp = next; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index fe7ac3a83194..40c33a7554c0 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -63,6 +63,9 @@ struct ethtool_rx_list { /* Length for FCB */ #define GMAC_FCB_LEN 8 +/* Length for TxPAL */ +#define GMAC_TXPAL_LEN 16 + /* Default padding amount */ #define DEFAULT_PADDING 2 diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 0b3567ab8121..85e2c6cd9708 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -98,6 +98,7 @@ struct ltq_etop_chan { struct ltq_etop_priv { struct net_device *netdev; + struct platform_device *pdev; struct ltq_eth_data *pldata; struct resource *res; @@ -436,7 +437,8 @@ ltq_etop_mdio_init(struct net_device *dev) priv->mii_bus->read = ltq_etop_mdio_rd; priv->mii_bus->write = ltq_etop_mdio_wr; priv->mii_bus->name = "ltq_mii"; - snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + priv->pdev->name, priv->pdev->id); priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); if (!priv->mii_bus->irq) { err = -ENOMEM; @@ -734,6 +736,7 @@ ltq_etop_probe(struct platform_device *pdev) dev->ethtool_ops = <q_etop_ethtool_ops; priv = netdev_priv(dev); priv->res = res; + priv->pdev = pdev; priv->pldata = dev_get_platdata(&pdev->dev); priv->netdev = dev; spin_lock_init(&priv->lock); diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 80aab4e5d695..9c049d2cb97d 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2613,7 +2613,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) msp->smi_bus->name = "mv643xx_eth smi"; msp->smi_bus->read = smi_bus_read; msp->smi_bus->write = smi_bus_write, - snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); + snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d", + pdev->name, pdev->id); msp->smi_bus->parent = &pdev->dev; msp->smi_bus->phy_mask = 0xffffffff; if (mdiobus_register(msp->smi_bus) < 0) diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 5ec409e3da09..953ba5851f7b 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1552,7 +1552,8 @@ static int pxa168_eth_probe(struct platform_device *pdev) pep->smi_bus->name = "pxa168_eth smi"; pep->smi_bus->read = pxa168_smi_read; pep->smi_bus->write = pxa168_smi_write; - snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%d", pdev->id); + snprintf(pep->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d", + pdev->name, pdev->id); pep->smi_bus->parent = &pdev->dev; pep->smi_bus->phy_mask = 0xffffffff; err = mdiobus_register(pep->smi_bus); diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 6ed09a85f035..e52cd310ae76 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -746,7 +746,7 @@ #define MAC_ADDR_ORDER(i) (ETH_ALEN - 1 - (i)) #define MAX_ETHERNET_BODY_SIZE 1500 -#define ETHERNET_HEADER_SIZE 14 +#define ETHERNET_HEADER_SIZE (14 + VLAN_HLEN) #define MAX_ETHERNET_PACKET_SIZE \ (MAX_ETHERNET_BODY_SIZE + ETHERNET_HEADER_SIZE) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index fc9bda9bc36c..6ece4295d78f 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1702,7 +1702,8 @@ static int sh_mdio_init(struct net_device *ndev, int id, /* Hook up MII support for ethtool */ mdp->mii_bus->name = "sh_mii"; mdp->mii_bus->parent = &ndev->dev; - snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%x", id); + snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + mdp->pdev->name, pdid); /* PHY IRQ */ mdp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c index a7ff8ea342b4..22e9c0181ce8 100644 --- a/drivers/net/ethernet/s6gmac.c +++ b/drivers/net/ethernet/s6gmac.c @@ -1004,7 +1004,7 @@ static int __devinit s6gmac_probe(struct platform_device *pdev) mb->write = s6mii_write; mb->reset = s6mii_reset; mb->priv = pd; - snprintf(mb->id, MII_BUS_ID_SIZE, "0"); + snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id); mb->phy_mask = ~(1 << 0); mb->irq = &pd->mii.irq[0]; for (i = 0; i < PHY_MAX_ADDR; i++) { diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 9d0b8ced0234..24d2df068d71 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1044,7 +1044,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, } pdata->mii_bus->name = SMSC_MDIONAME; - snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); + snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); pdata->mii_bus->priv = pdata; pdata->mii_bus->read = smsc911x_mii_read; pdata->mii_bus->write = smsc911x_mii_write; diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 41e6b33e1b08..c07cfe989f6e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -22,6 +22,7 @@ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> *******************************************************************************/ +#include <linux/kernel.h> #include <linux/io.h> #include "mmc.h" diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 3738b4700548..96fa2da30763 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -307,7 +307,7 @@ static int stmmac_init_phy(struct net_device *dev) priv->speed = 0; priv->oldduplex = -1; - snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->plat->bus_id); + snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", priv->plat->bus_id); snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, priv->plat->phy_addr); pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); @@ -772,7 +772,7 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv) dwmac_mmc_ctrl(priv->ioaddr, mode); memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); } else - pr_info(" No MAC Management Counters available"); + pr_info(" No MAC Management Counters available\n"); } static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 51f441233962..da4a1042523a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -158,7 +158,8 @@ int stmmac_mdio_register(struct net_device *ndev) new_bus->read = &stmmac_mdio_read; new_bus->write = &stmmac_mdio_write; new_bus->reset = &stmmac_mdio_reset; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", mdio_bus_data->bus_id); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x", + new_bus->name, mdio_bus_data->bus_id); new_bus->priv = ndev; new_bus->irq = irqlist; new_bus->phy_mask = mdio_bus_data->phy_mask; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 7b1594f4944e..1ac83243649a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -62,7 +62,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) priv = stmmac_dvr_probe(&(pdev->dev), plat_dat); if (!priv) { pr_err("%s: main drivr probe failed", __func__); - goto out_release_region; + goto out_unmap; } priv->ioaddr = addr; diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index aaac0c7ad111..4d9a28ffd3c3 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -1269,7 +1269,7 @@ int __devinit cpmac_init(void) } cpmac_mii->phy_mask = ~(mask | 0x80000000); - snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "1"); + snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "cpmac-1"); res = mdiobus_register(cpmac_mii); if (res) diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 7615040df756..ef7c9c17bfff 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -313,7 +313,8 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev) data->bus->reset = davinci_mdio_reset, data->bus->parent = dev; data->bus->priv = data; - snprintf(data->bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); + snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); data->clk = clk_get(dev, NULL); if (IS_ERR(data->clk)) { diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index a9ce01bafd20..164fb775d7b3 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1604,7 +1604,7 @@ tsi108_init_one(struct platform_device *pdev) data->phyregs = ioremap(einfo->phyregs, 0x400); if (NULL == data->phyregs) { err = -ENOMEM; - goto regs_fail; + goto phyregs_fail; } /* MII setup */ data->mii_if.dev = dev; @@ -1663,9 +1663,11 @@ tsi108_init_one(struct platform_device *pdev) return 0; register_fail: - iounmap(data->regs); iounmap(data->phyregs); +phyregs_fail: + iounmap(data->regs); + regs_fail: free_netdev(dev); return err; diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index 5c4983b2870a..10b18eb63d25 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -39,10 +39,9 @@ /* A few user-configurable values. These may be modified when a driver module is loaded. */ - -#define DEBUG -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -static int max_interrupt_work = 20; +static int debug = 0; +#define RHINE_MSG_DEFAULT \ + (0x0000) /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ @@ -128,12 +127,10 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>"); MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); MODULE_LICENSE("GPL"); -module_param(max_interrupt_work, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); module_param(avoid_D3, bool, 0); -MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt"); -MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)"); +MODULE_PARM_DESC(debug, "VIA Rhine debug message flags"); MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)"); @@ -351,16 +348,25 @@ static const int mmio_verify_registers[] = { /* Bits in the interrupt status/mask registers. */ enum intr_status_bits { - IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020, - IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210, - IntrPCIErr=0x0040, - IntrStatsMax=0x0080, IntrRxEarly=0x0100, - IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000, - IntrTxAborted=0x2000, IntrLinkChange=0x4000, - IntrRxWakeUp=0x8000, - IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260, - IntrTxDescRace=0x080000, /* mapped from IntrStatus2 */ - IntrTxErrSummary=0x082218, + IntrRxDone = 0x0001, + IntrTxDone = 0x0002, + IntrRxErr = 0x0004, + IntrTxError = 0x0008, + IntrRxEmpty = 0x0020, + IntrPCIErr = 0x0040, + IntrStatsMax = 0x0080, + IntrRxEarly = 0x0100, + IntrTxUnderrun = 0x0210, + IntrRxOverflow = 0x0400, + IntrRxDropped = 0x0800, + IntrRxNoBuf = 0x1000, + IntrTxAborted = 0x2000, + IntrLinkChange = 0x4000, + IntrRxWakeUp = 0x8000, + IntrTxDescRace = 0x080000, /* mapped from IntrStatus2 */ + IntrNormalSummary = IntrRxDone | IntrTxDone, + IntrTxErrSummary = IntrTxDescRace | IntrTxAborted | IntrTxError | + IntrTxUnderrun, }; /* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */ @@ -439,8 +445,13 @@ struct rhine_private { struct net_device *dev; struct napi_struct napi; spinlock_t lock; + struct mutex task_lock; + bool task_enable; + struct work_struct slow_event_task; struct work_struct reset_task; + u32 msg_enable; + /* Frequently used values: keep some adjacent for cache effect. */ u32 quirks; struct rx_desc *rx_head_desc; @@ -476,41 +487,50 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static int rhine_open(struct net_device *dev); static void rhine_reset_task(struct work_struct *work); +static void rhine_slow_event_task(struct work_struct *work); static void rhine_tx_timeout(struct net_device *dev); static netdev_tx_t rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t rhine_interrupt(int irq, void *dev_instance); static void rhine_tx(struct net_device *dev); static int rhine_rx(struct net_device *dev, int limit); -static void rhine_error(struct net_device *dev, int intr_status); static void rhine_set_rx_mode(struct net_device *dev); static struct net_device_stats *rhine_get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); -static void rhine_shutdown (struct pci_dev *pdev); static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid); static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid); -static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr); -static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr); -static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask); -static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask); -static void rhine_init_cam_filter(struct net_device *dev); -static void rhine_update_vcam(struct net_device *dev); - -#define RHINE_WAIT_FOR(condition) \ -do { \ - int i = 1024; \ - while (!(condition) && --i) \ - ; \ - if (debug > 1 && i < 512) \ - pr_info("%4d cycles used @ %s:%d\n", \ - 1024 - i, __func__, __LINE__); \ -} while (0) - -static inline u32 get_intr_status(struct net_device *dev) +static void rhine_restart_tx(struct net_device *dev); + +static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool high) +{ + void __iomem *ioaddr = rp->base; + int i; + + for (i = 0; i < 1024; i++) { + if (high ^ !!(ioread8(ioaddr + reg) & mask)) + break; + udelay(10); + } + if (i > 64) { + netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle " + "count: %04d\n", high ? "high" : "low", reg, mask, i); + } +} + +static void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask) +{ + rhine_wait_bit(rp, reg, mask, true); +} + +static void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask) +{ + rhine_wait_bit(rp, reg, mask, false); +} + +static u32 rhine_get_events(struct rhine_private *rp) { - struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; u32 intr_status; @@ -521,6 +541,16 @@ static inline u32 get_intr_status(struct net_device *dev) return intr_status; } +static void rhine_ack_events(struct rhine_private *rp, u32 mask) +{ + void __iomem *ioaddr = rp->base; + + if (rp->quirks & rqStatusWBRace) + iowrite8(mask >> 16, ioaddr + IntrStatus2); + iowrite16(mask, ioaddr + IntrStatus); + mmiowb(); +} + /* * Get power related registers into sane state. * Notify user about past WOL event. @@ -585,6 +615,7 @@ static void rhine_chip_reset(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; + u8 cmd1; iowrite8(Cmd1Reset, ioaddr + ChipCmd1); IOSYNC; @@ -597,13 +628,12 @@ static void rhine_chip_reset(struct net_device *dev) iowrite8(0x40, ioaddr + MiscCmd); /* Reset can take somewhat longer (rare) */ - RHINE_WAIT_FOR(!(ioread8(ioaddr + ChipCmd1) & Cmd1Reset)); + rhine_wait_bit_low(rp, ChipCmd1, Cmd1Reset); } - if (debug > 1) - netdev_info(dev, "Reset %s\n", - (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ? - "failed" : "succeeded"); + cmd1 = ioread8(ioaddr + ChipCmd1); + netif_info(rp, hw, dev, "Reset %s\n", (cmd1 & Cmd1Reset) ? + "failed" : "succeeded"); } #ifdef USE_MMIO @@ -629,9 +659,15 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; + int i; outb(0x20, pioaddr + MACRegEEcsr); - RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20)); + for (i = 0; i < 1024; i++) { + if (!(inb(pioaddr + MACRegEEcsr) & 0x20)) + break; + } + if (i > 512) + pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__); #ifdef USE_MMIO /* @@ -657,23 +693,127 @@ static void rhine_poll(struct net_device *dev) } #endif +static void rhine_kick_tx_threshold(struct rhine_private *rp) +{ + if (rp->tx_thresh < 0xe0) { + void __iomem *ioaddr = rp->base; + + rp->tx_thresh += 0x20; + BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig); + } +} + +static void rhine_tx_err(struct rhine_private *rp, u32 status) +{ + struct net_device *dev = rp->dev; + + if (status & IntrTxAborted) { + netif_info(rp, tx_err, dev, + "Abort %08x, frame dropped\n", status); + } + + if (status & IntrTxUnderrun) { + rhine_kick_tx_threshold(rp); + netif_info(rp, tx_err ,dev, "Transmitter underrun, " + "Tx threshold now %02x\n", rp->tx_thresh); + } + + if (status & IntrTxDescRace) + netif_info(rp, tx_err, dev, "Tx descriptor write-back race\n"); + + if ((status & IntrTxError) && + (status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace)) == 0) { + rhine_kick_tx_threshold(rp); + netif_info(rp, tx_err, dev, "Unspecified error. " + "Tx threshold now %02x\n", rp->tx_thresh); + } + + rhine_restart_tx(dev); +} + +static void rhine_update_rx_crc_and_missed_errord(struct rhine_private *rp) +{ + void __iomem *ioaddr = rp->base; + struct net_device_stats *stats = &rp->dev->stats; + + stats->rx_crc_errors += ioread16(ioaddr + RxCRCErrs); + stats->rx_missed_errors += ioread16(ioaddr + RxMissed); + + /* + * Clears the "tally counters" for CRC errors and missed frames(?). + * It has been reported that some chips need a write of 0 to clear + * these, for others the counters are set to 1 when written to and + * instead cleared when read. So we clear them both ways ... + */ + iowrite32(0, ioaddr + RxMissed); + ioread16(ioaddr + RxCRCErrs); + ioread16(ioaddr + RxMissed); +} + +#define RHINE_EVENT_NAPI_RX (IntrRxDone | \ + IntrRxErr | \ + IntrRxEmpty | \ + IntrRxOverflow | \ + IntrRxDropped | \ + IntrRxNoBuf | \ + IntrRxWakeUp) + +#define RHINE_EVENT_NAPI_TX_ERR (IntrTxError | \ + IntrTxAborted | \ + IntrTxUnderrun | \ + IntrTxDescRace) +#define RHINE_EVENT_NAPI_TX (IntrTxDone | RHINE_EVENT_NAPI_TX_ERR) + +#define RHINE_EVENT_NAPI (RHINE_EVENT_NAPI_RX | \ + RHINE_EVENT_NAPI_TX | \ + IntrStatsMax) +#define RHINE_EVENT_SLOW (IntrPCIErr | IntrLinkChange) +#define RHINE_EVENT (RHINE_EVENT_NAPI | RHINE_EVENT_SLOW) + static int rhine_napipoll(struct napi_struct *napi, int budget) { struct rhine_private *rp = container_of(napi, struct rhine_private, napi); struct net_device *dev = rp->dev; void __iomem *ioaddr = rp->base; - int work_done; + u16 enable_mask = RHINE_EVENT & 0xffff; + int work_done = 0; + u32 status; + + status = rhine_get_events(rp); + rhine_ack_events(rp, status & ~RHINE_EVENT_SLOW); + + if (status & RHINE_EVENT_NAPI_RX) + work_done += rhine_rx(dev, budget); + + if (status & RHINE_EVENT_NAPI_TX) { + if (status & RHINE_EVENT_NAPI_TX_ERR) { + /* Avoid scavenging before Tx engine turned off */ + rhine_wait_bit_low(rp, ChipCmd, CmdTxOn); + if (ioread8(ioaddr + ChipCmd) & CmdTxOn) + netif_warn(rp, tx_err, dev, "Tx still on\n"); + } - work_done = rhine_rx(dev, budget); + rhine_tx(dev); + + if (status & RHINE_EVENT_NAPI_TX_ERR) + rhine_tx_err(rp, status); + } + + if (status & IntrStatsMax) { + spin_lock(&rp->lock); + rhine_update_rx_crc_and_missed_errord(rp); + spin_unlock(&rp->lock); + } + + if (status & RHINE_EVENT_SLOW) { + enable_mask &= ~RHINE_EVENT_SLOW; + schedule_work(&rp->slow_event_task); + } if (work_done < budget) { napi_complete(napi); - - iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | - IntrRxDropped | IntrRxNoBuf | IntrTxAborted | - IntrTxDone | IntrTxError | IntrTxUnderrun | - IntrPCIErr | IntrStatsMax | IntrLinkChange, - ioaddr + IntrEnable); + iowrite16(enable_mask, ioaddr + IntrEnable); + mmiowb(); } return work_done; } @@ -797,6 +937,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, rp->quirks = quirks; rp->pioaddr = pioaddr; rp->pdev = pdev; + rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT); rc = pci_request_regions(pdev, DRV_NAME); if (rc) @@ -856,7 +997,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, dev->irq = pdev->irq; spin_lock_init(&rp->lock); + mutex_init(&rp->task_lock); INIT_WORK(&rp->reset_task, rhine_reset_task); + INIT_WORK(&rp->slow_event_task, rhine_slow_event_task); rp->mii_if.dev = dev; rp->mii_if.mdio_read = mdio_read; @@ -916,8 +1059,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, } } rp->mii_if.phy_id = phy_id; - if (debug > 1 && avoid_D3) - netdev_info(dev, "No D3 power state at shutdown\n"); + if (avoid_D3) + netif_info(rp, probe, dev, "No D3 power state at shutdown\n"); return 0; @@ -1093,7 +1236,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - mii_check_media(&rp->mii_if, debug, init_media); + mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media); if (rp->mii_if.full_duplex) iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex, @@ -1101,24 +1244,26 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) else iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, ioaddr + ChipCmd1); - if (debug > 1) - netdev_info(dev, "force_media %d, carrier %d\n", - rp->mii_if.force_media, netif_carrier_ok(dev)); + + netif_info(rp, link, dev, "force_media %d, carrier %d\n", + rp->mii_if.force_media, netif_carrier_ok(dev)); } /* Called after status of force_media possibly changed */ static void rhine_set_carrier(struct mii_if_info *mii) { + struct net_device *dev = mii->dev; + struct rhine_private *rp = netdev_priv(dev); + if (mii->force_media) { /* autoneg is off: Link is always assumed to be up */ - if (!netif_carrier_ok(mii->dev)) - netif_carrier_on(mii->dev); - } - else /* Let MMI library update carrier status */ - rhine_check_media(mii->dev, 0); - if (debug > 1) - netdev_info(mii->dev, "force_media %d, carrier %d\n", - mii->force_media, netif_carrier_ok(mii->dev)); + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + } else /* Let MMI library update carrier status */ + rhine_check_media(dev, 0); + + netif_info(rp, link, dev, "force_media %d, carrier %d\n", + mii->force_media, netif_carrier_ok(dev)); } /** @@ -1266,10 +1411,10 @@ static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) { struct rhine_private *rp = netdev_priv(dev); - spin_lock_irq(&rp->lock); + spin_lock_bh(&rp->lock); set_bit(vid, rp->active_vlans); rhine_update_vcam(dev); - spin_unlock_irq(&rp->lock); + spin_unlock_bh(&rp->lock); return 0; } @@ -1277,10 +1422,10 @@ static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct rhine_private *rp = netdev_priv(dev); - spin_lock_irq(&rp->lock); + spin_lock_bh(&rp->lock); clear_bit(vid, rp->active_vlans); rhine_update_vcam(dev); - spin_unlock_irq(&rp->lock); + spin_unlock_bh(&rp->lock); return 0; } @@ -1310,12 +1455,7 @@ static void init_registers(struct net_device *dev) napi_enable(&rp->napi); - /* Enable interrupts by setting the interrupt mask. */ - iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | - IntrRxDropped | IntrRxNoBuf | IntrTxAborted | - IntrTxDone | IntrTxError | IntrTxUnderrun | - IntrPCIErr | IntrStatsMax | IntrLinkChange, - ioaddr + IntrEnable); + iowrite16(RHINE_EVENT & 0xffff, ioaddr + IntrEnable); iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8), ioaddr + ChipCmd); @@ -1323,23 +1463,27 @@ static void init_registers(struct net_device *dev) } /* Enable MII link status auto-polling (required for IntrLinkChange) */ -static void rhine_enable_linkmon(void __iomem *ioaddr) +static void rhine_enable_linkmon(struct rhine_private *rp) { + void __iomem *ioaddr = rp->base; + iowrite8(0, ioaddr + MIICmd); iowrite8(MII_BMSR, ioaddr + MIIRegAddr); iowrite8(0x80, ioaddr + MIICmd); - RHINE_WAIT_FOR((ioread8(ioaddr + MIIRegAddr) & 0x20)); + rhine_wait_bit_high(rp, MIIRegAddr, 0x20); iowrite8(MII_BMSR | 0x40, ioaddr + MIIRegAddr); } /* Disable MII link status auto-polling (required for MDIO access) */ -static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks) +static void rhine_disable_linkmon(struct rhine_private *rp) { + void __iomem *ioaddr = rp->base; + iowrite8(0, ioaddr + MIICmd); - if (quirks & rqRhineI) { + if (rp->quirks & rqRhineI) { iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR /* Can be called from ISR. Evil. */ @@ -1348,13 +1492,13 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks) /* 0x80 must be set immediately before turning it off */ iowrite8(0x80, ioaddr + MIICmd); - RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x20); + rhine_wait_bit_high(rp, MIIRegAddr, 0x20); /* Heh. Now clear 0x80 again. */ iowrite8(0, ioaddr + MIICmd); } else - RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x80); + rhine_wait_bit_high(rp, MIIRegAddr, 0x80); } /* Read and write over the MII Management Data I/O (MDIO) interface. */ @@ -1365,16 +1509,16 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum) void __iomem *ioaddr = rp->base; int result; - rhine_disable_linkmon(ioaddr, rp->quirks); + rhine_disable_linkmon(rp); /* rhine_disable_linkmon already cleared MIICmd */ iowrite8(phy_id, ioaddr + MIIPhyAddr); iowrite8(regnum, ioaddr + MIIRegAddr); iowrite8(0x40, ioaddr + MIICmd); /* Trigger read */ - RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x40)); + rhine_wait_bit_low(rp, MIICmd, 0x40); result = ioread16(ioaddr + MIIData); - rhine_enable_linkmon(ioaddr); + rhine_enable_linkmon(rp); return result; } @@ -1383,16 +1527,33 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; - rhine_disable_linkmon(ioaddr, rp->quirks); + rhine_disable_linkmon(rp); /* rhine_disable_linkmon already cleared MIICmd */ iowrite8(phy_id, ioaddr + MIIPhyAddr); iowrite8(regnum, ioaddr + MIIRegAddr); iowrite16(value, ioaddr + MIIData); iowrite8(0x20, ioaddr + MIICmd); /* Trigger write */ - RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x20)); + rhine_wait_bit_low(rp, MIICmd, 0x20); - rhine_enable_linkmon(ioaddr); + rhine_enable_linkmon(rp); +} + +static void rhine_task_disable(struct rhine_private *rp) +{ + mutex_lock(&rp->task_lock); + rp->task_enable = false; + mutex_unlock(&rp->task_lock); + + cancel_work_sync(&rp->slow_event_task); + cancel_work_sync(&rp->reset_task); +} + +static void rhine_task_enable(struct rhine_private *rp) +{ + mutex_lock(&rp->task_lock); + rp->task_enable = true; + mutex_unlock(&rp->task_lock); } static int rhine_open(struct net_device *dev) @@ -1406,8 +1567,7 @@ static int rhine_open(struct net_device *dev) if (rc) return rc; - if (debug > 1) - netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq); + netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->pdev->irq); rc = alloc_ring(dev); if (rc) { @@ -1417,11 +1577,12 @@ static int rhine_open(struct net_device *dev) alloc_rbufs(dev); alloc_tbufs(dev); rhine_chip_reset(dev); + rhine_task_enable(rp); init_registers(dev); - if (debug > 2) - netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n", - __func__, ioread16(ioaddr + ChipCmd), - mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); + + netif_dbg(rp, ifup, dev, "%s() Done - status %04x MII status: %04x\n", + __func__, ioread16(ioaddr + ChipCmd), + mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); netif_start_queue(dev); @@ -1434,11 +1595,12 @@ static void rhine_reset_task(struct work_struct *work) reset_task); struct net_device *dev = rp->dev; - /* protect against concurrent rx interrupts */ - disable_irq(rp->pdev->irq); + mutex_lock(&rp->task_lock); - napi_disable(&rp->napi); + if (!rp->task_enable) + goto out_unlock; + napi_disable(&rp->napi); spin_lock_bh(&rp->lock); /* clear all descriptors */ @@ -1452,11 +1614,13 @@ static void rhine_reset_task(struct work_struct *work) init_registers(dev); spin_unlock_bh(&rp->lock); - enable_irq(rp->pdev->irq); dev->trans_start = jiffies; /* prevent tx timeout */ dev->stats.tx_errors++; netif_wake_queue(dev); + +out_unlock: + mutex_unlock(&rp->task_lock); } static void rhine_tx_timeout(struct net_device *dev) @@ -1477,7 +1641,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; unsigned entry; - unsigned long flags; /* Caution: the write order is important here, set the field with the "ownership" bits last. */ @@ -1529,7 +1692,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, rp->tx_ring[entry].tx_status = 0; /* lock eth irq */ - spin_lock_irqsave(&rp->lock, flags); wmb(); rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn); wmb(); @@ -1550,78 +1712,43 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb, if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN) netif_stop_queue(dev); - spin_unlock_irqrestore(&rp->lock, flags); + netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n", + rp->cur_tx - 1, entry); - if (debug > 4) { - netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n", - rp->cur_tx-1, entry); - } return NETDEV_TX_OK; } +static void rhine_irq_disable(struct rhine_private *rp) +{ + iowrite16(0x0000, rp->base + IntrEnable); + mmiowb(); +} + /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct rhine_private *rp = netdev_priv(dev); - void __iomem *ioaddr = rp->base; - u32 intr_status; - int boguscnt = max_interrupt_work; + u32 status; int handled = 0; - while ((intr_status = get_intr_status(dev))) { - handled = 1; - - /* Acknowledge all of the current interrupt sources ASAP. */ - if (intr_status & IntrTxDescRace) - iowrite8(0x08, ioaddr + IntrStatus2); - iowrite16(intr_status & 0xffff, ioaddr + IntrStatus); - IOSYNC; + status = rhine_get_events(rp); - if (debug > 4) - netdev_dbg(dev, "Interrupt, status %08x\n", - intr_status); - - if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped | - IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) { - iowrite16(IntrTxAborted | - IntrTxDone | IntrTxError | IntrTxUnderrun | - IntrPCIErr | IntrStatsMax | IntrLinkChange, - ioaddr + IntrEnable); - - napi_schedule(&rp->napi); - } + netif_dbg(rp, intr, dev, "Interrupt, status %08x\n", status); - if (intr_status & (IntrTxErrSummary | IntrTxDone)) { - if (intr_status & IntrTxErrSummary) { - /* Avoid scavenging before Tx engine turned off */ - RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn)); - if (debug > 2 && - ioread8(ioaddr+ChipCmd) & CmdTxOn) - netdev_warn(dev, - "%s: Tx engine still on\n", - __func__); - } - rhine_tx(dev); - } + if (status & RHINE_EVENT) { + handled = 1; - /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & (IntrPCIErr | IntrLinkChange | - IntrStatsMax | IntrTxError | IntrTxAborted | - IntrTxUnderrun | IntrTxDescRace)) - rhine_error(dev, intr_status); + rhine_irq_disable(rp); + napi_schedule(&rp->napi); + } - if (--boguscnt < 0) { - netdev_warn(dev, "Too much work at interrupt, status=%#08x\n", - intr_status); - break; - } + if (status & ~(IntrLinkChange | IntrStatsMax | RHINE_EVENT_NAPI)) { + netif_err(rp, intr, dev, "Something Wicked happened! %08x\n", + status); } - if (debug > 3) - netdev_dbg(dev, "exiting interrupt, status=%08x\n", - ioread16(ioaddr + IntrStatus)); return IRQ_RETVAL(handled); } @@ -1632,20 +1759,16 @@ static void rhine_tx(struct net_device *dev) struct rhine_private *rp = netdev_priv(dev); int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE; - spin_lock(&rp->lock); - /* find and cleanup dirty tx descriptors */ while (rp->dirty_tx != rp->cur_tx) { txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status); - if (debug > 6) - netdev_dbg(dev, "Tx scavenge %d status %08x\n", - entry, txstatus); + netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n", + entry, txstatus); if (txstatus & DescOwn) break; if (txstatus & 0x8000) { - if (debug > 1) - netdev_dbg(dev, "Transmit error, Tx status %08x\n", - txstatus); + netif_dbg(rp, tx_done, dev, + "Transmit error, Tx status %08x\n", txstatus); dev->stats.tx_errors++; if (txstatus & 0x0400) dev->stats.tx_carrier_errors++; @@ -1667,10 +1790,8 @@ static void rhine_tx(struct net_device *dev) dev->stats.collisions += (txstatus >> 3) & 0x0F; else dev->stats.collisions += txstatus & 0x0F; - if (debug > 6) - netdev_dbg(dev, "collisions: %1.1x:%1.1x\n", - (txstatus >> 3) & 0xF, - txstatus & 0xF); + netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n", + (txstatus >> 3) & 0xF, txstatus & 0xF); dev->stats.tx_bytes += rp->tx_skbuff[entry]->len; dev->stats.tx_packets++; } @@ -1687,8 +1808,6 @@ static void rhine_tx(struct net_device *dev) } if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4) netif_wake_queue(dev); - - spin_unlock(&rp->lock); } /** @@ -1713,11 +1832,8 @@ static int rhine_rx(struct net_device *dev, int limit) int count; int entry = rp->cur_rx % RX_RING_SIZE; - if (debug > 4) { - netdev_dbg(dev, "%s(), entry %d status %08x\n", - __func__, entry, - le32_to_cpu(rp->rx_head_desc->rx_status)); - } + netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__, + entry, le32_to_cpu(rp->rx_head_desc->rx_status)); /* If EOP is set on the next entry, it's a new packet. Send it up. */ for (count = 0; count < limit; ++count) { @@ -1729,9 +1845,8 @@ static int rhine_rx(struct net_device *dev, int limit) if (desc_status & DescOwn) break; - if (debug > 4) - netdev_dbg(dev, "%s() status is %08x\n", - __func__, desc_status); + netif_dbg(rp, rx_status, dev, "%s() status %08x\n", __func__, + desc_status); if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { if ((desc_status & RxWholePkt) != RxWholePkt) { @@ -1747,9 +1862,9 @@ static int rhine_rx(struct net_device *dev, int limit) dev->stats.rx_length_errors++; } else if (desc_status & RxErr) { /* There was a error. */ - if (debug > 2) - netdev_dbg(dev, "%s() Rx error was %08x\n", - __func__, desc_status); + netif_dbg(rp, rx_err, dev, + "%s() Rx error %08x\n", __func__, + desc_status); dev->stats.rx_errors++; if (desc_status & 0x0030) dev->stats.rx_length_errors++; @@ -1839,19 +1954,6 @@ static int rhine_rx(struct net_device *dev, int limit) return count; } -/* - * Clears the "tally counters" for CRC errors and missed frames(?). - * It has been reported that some chips need a write of 0 to clear - * these, for others the counters are set to 1 when written to and - * instead cleared when read. So we clear them both ways ... - */ -static inline void clear_tally_counters(void __iomem *ioaddr) -{ - iowrite32(0, ioaddr + RxMissed); - ioread16(ioaddr + RxCRCErrs); - ioread16(ioaddr + RxMissed); -} - static void rhine_restart_tx(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; @@ -1862,7 +1964,7 @@ static void rhine_restart_tx(struct net_device *dev) { * If new errors occurred, we need to sort them out before doing Tx. * In that case the ISR will be back here RSN anyway. */ - intr_status = get_intr_status(dev); + intr_status = rhine_get_events(rp); if ((intr_status & IntrTxErrSummary) == 0) { @@ -1883,79 +1985,50 @@ static void rhine_restart_tx(struct net_device *dev) { } else { /* This should never happen */ - if (debug > 1) - netdev_warn(dev, "%s() Another error occurred %08x\n", - __func__, intr_status); + netif_warn(rp, tx_err, dev, "another error occurred %08x\n", + intr_status); } } -static void rhine_error(struct net_device *dev, int intr_status) +static void rhine_slow_event_task(struct work_struct *work) { - struct rhine_private *rp = netdev_priv(dev); - void __iomem *ioaddr = rp->base; + struct rhine_private *rp = + container_of(work, struct rhine_private, slow_event_task); + struct net_device *dev = rp->dev; + u32 intr_status; - spin_lock(&rp->lock); + mutex_lock(&rp->task_lock); + + if (!rp->task_enable) + goto out_unlock; + + intr_status = rhine_get_events(rp); + rhine_ack_events(rp, intr_status & RHINE_EVENT_SLOW); if (intr_status & IntrLinkChange) rhine_check_media(dev, 0); - if (intr_status & IntrStatsMax) { - dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); - clear_tally_counters(ioaddr); - } - if (intr_status & IntrTxAborted) { - if (debug > 1) - netdev_info(dev, "Abort %08x, frame dropped\n", - intr_status); - } - if (intr_status & IntrTxUnderrun) { - if (rp->tx_thresh < 0xE0) - BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); - if (debug > 1) - netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n", - rp->tx_thresh); - } - if (intr_status & IntrTxDescRace) { - if (debug > 2) - netdev_info(dev, "Tx descriptor write-back race\n"); - } - if ((intr_status & IntrTxError) && - (intr_status & (IntrTxAborted | - IntrTxUnderrun | IntrTxDescRace)) == 0) { - if (rp->tx_thresh < 0xE0) { - BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig); - } - if (debug > 1) - netdev_info(dev, "Unspecified error. Tx threshold now %02x\n", - rp->tx_thresh); - } - if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace | - IntrTxError)) - rhine_restart_tx(dev); - - if (intr_status & ~(IntrLinkChange | IntrStatsMax | IntrTxUnderrun | - IntrTxError | IntrTxAborted | IntrNormalSummary | - IntrTxDescRace)) { - if (debug > 1) - netdev_err(dev, "Something Wicked happened! %08x\n", - intr_status); - } - spin_unlock(&rp->lock); + if (intr_status & IntrPCIErr) + netif_warn(rp, hw, dev, "PCI error\n"); + + napi_disable(&rp->napi); + rhine_irq_disable(rp); + /* Slow and safe. Consider __napi_schedule as a replacement ? */ + napi_enable(&rp->napi); + napi_schedule(&rp->napi); + +out_unlock: + mutex_unlock(&rp->task_lock); } static struct net_device_stats *rhine_get_stats(struct net_device *dev) { struct rhine_private *rp = netdev_priv(dev); - void __iomem *ioaddr = rp->base; - unsigned long flags; - spin_lock_irqsave(&rp->lock, flags); - dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); - dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); - clear_tally_counters(ioaddr); - spin_unlock_irqrestore(&rp->lock, flags); + spin_lock_bh(&rp->lock); + rhine_update_rx_crc_and_missed_errord(rp); + spin_unlock_bh(&rp->lock); return &dev->stats; } @@ -2022,9 +2095,9 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct rhine_private *rp = netdev_priv(dev); int rc; - spin_lock_irq(&rp->lock); + mutex_lock(&rp->task_lock); rc = mii_ethtool_gset(&rp->mii_if, cmd); - spin_unlock_irq(&rp->lock); + mutex_unlock(&rp->task_lock); return rc; } @@ -2034,10 +2107,10 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) struct rhine_private *rp = netdev_priv(dev); int rc; - spin_lock_irq(&rp->lock); + mutex_lock(&rp->task_lock); rc = mii_ethtool_sset(&rp->mii_if, cmd); - spin_unlock_irq(&rp->lock); rhine_set_carrier(&rp->mii_if); + mutex_unlock(&rp->task_lock); return rc; } @@ -2058,12 +2131,16 @@ static u32 netdev_get_link(struct net_device *dev) static u32 netdev_get_msglevel(struct net_device *dev) { - return debug; + struct rhine_private *rp = netdev_priv(dev); + + return rp->msg_enable; } static void netdev_set_msglevel(struct net_device *dev, u32 value) { - debug = value; + struct rhine_private *rp = netdev_priv(dev); + + rp->msg_enable = value; } static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -2119,10 +2196,10 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!netif_running(dev)) return -EINVAL; - spin_lock_irq(&rp->lock); + mutex_lock(&rp->task_lock); rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL); - spin_unlock_irq(&rp->lock); rhine_set_carrier(&rp->mii_if); + mutex_unlock(&rp->task_lock); return rc; } @@ -2132,27 +2209,21 @@ static int rhine_close(struct net_device *dev) struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; + rhine_task_disable(rp); napi_disable(&rp->napi); - cancel_work_sync(&rp->reset_task); netif_stop_queue(dev); - spin_lock_irq(&rp->lock); - - if (debug > 1) - netdev_dbg(dev, "Shutting down ethercard, status was %04x\n", - ioread16(ioaddr + ChipCmd)); + netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n", + ioread16(ioaddr + ChipCmd)); /* Switch to loopback mode to avoid hardware races. */ iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig); - /* Disable interrupts by clearing the interrupt mask. */ - iowrite16(0x0000, ioaddr + IntrEnable); + rhine_irq_disable(rp); /* Stop the chip's Tx and Rx processes. */ iowrite16(CmdStop, ioaddr + ChipCmd); - spin_unlock_irq(&rp->lock); - free_irq(rp->pdev->irq, dev); free_rbufs(dev); free_tbufs(dev); @@ -2192,6 +2263,8 @@ static void rhine_shutdown (struct pci_dev *pdev) if (rp->quirks & rq6patterns) iowrite8(0x04, ioaddr + WOLcgClr); + spin_lock(&rp->lock); + if (rp->wolopts & WAKE_MAGIC) { iowrite8(WOLmagic, ioaddr + WOLcrSet); /* @@ -2216,58 +2289,46 @@ static void rhine_shutdown (struct pci_dev *pdev) iowrite8(ioread8(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW); } - /* Hit power state D3 (sleep) */ - if (!avoid_D3) - iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + spin_unlock(&rp->lock); - /* TODO: Check use of pci_enable_wake() */ + if (system_state == SYSTEM_POWER_OFF && !avoid_D3) { + iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); + pci_wake_from_d3(pdev, true); + pci_set_power_state(pdev, PCI_D3hot); + } } -#ifdef CONFIG_PM -static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int rhine_suspend(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); - unsigned long flags; if (!netif_running(dev)) return 0; + rhine_task_disable(rp); + rhine_irq_disable(rp); napi_disable(&rp->napi); netif_device_detach(dev); - pci_save_state(pdev); - spin_lock_irqsave(&rp->lock, flags); rhine_shutdown(pdev); - spin_unlock_irqrestore(&rp->lock, flags); - free_irq(dev->irq, dev); return 0; } -static int rhine_resume(struct pci_dev *pdev) +static int rhine_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); - unsigned long flags; - int ret; if (!netif_running(dev)) return 0; - if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev)) - netdev_err(dev, "request_irq failed\n"); - - ret = pci_set_power_state(pdev, PCI_D0); - if (debug > 1) - netdev_info(dev, "Entering power state D0 %s (%d)\n", - ret ? "failed" : "succeeded", ret); - - pci_restore_state(pdev); - - spin_lock_irqsave(&rp->lock, flags); #ifdef USE_MMIO enable_mmio(rp->pioaddr, rp->quirks); #endif @@ -2276,25 +2337,32 @@ static int rhine_resume(struct pci_dev *pdev) free_rbufs(dev); alloc_tbufs(dev); alloc_rbufs(dev); + rhine_task_enable(rp); + spin_lock_bh(&rp->lock); init_registers(dev); - spin_unlock_irqrestore(&rp->lock, flags); + spin_unlock_bh(&rp->lock); netif_device_attach(dev); return 0; } -#endif /* CONFIG_PM */ + +static SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume); +#define RHINE_PM_OPS (&rhine_pm_ops) + +#else + +#define RHINE_PM_OPS NULL + +#endif /* !CONFIG_PM_SLEEP */ static struct pci_driver rhine_driver = { .name = DRV_NAME, .id_table = rhine_pci_tbl, .probe = rhine_init_one, .remove = __devexit_p(rhine_remove_one), -#ifdef CONFIG_PM - .suspend = rhine_suspend, - .resume = rhine_resume, -#endif /* CONFIG_PM */ - .shutdown = rhine_shutdown, + .shutdown = rhine_shutdown, + .driver.pm = RHINE_PM_OPS, }; static struct dmi_system_id __initdata rhine_dmi_table[] = { diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index f45c85a84261..72a854f05bb8 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -529,7 +529,7 @@ static int ixp4xx_mdio_register(void) mdio_bus->name = "IXP4xx MII Bus"; mdio_bus->read = &ixp4xx_mdio_read; mdio_bus->write = &ixp4xx_mdio_write; - strcpy(mdio_bus->id, "0"); + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "ixp4xx-eth-0"); if ((err = mdiobus_register(mdio_bus))) mdiobus_free(mdio_bus); diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index d423d18b4ad6..e535137eb2d0 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -313,8 +313,12 @@ config TOSHIBA_FIR donauboe. config AU1000_FIR - tristate "Alchemy Au1000 SIR/FIR" + tristate "Alchemy IrDA SIR/FIR" depends on IRDA && MIPS_ALCHEMY + help + Say Y/M here to build suppor the the IrDA peripheral on the + Alchemy Au1000 and Au1100 SoCs. + Say M to build a module; it will be called au1k_ir.ko config SMC_IRCC_FIR tristate "SMSC IrCC (EXPERIMENTAL)" diff --git a/drivers/net/irda/au1000_ircc.h b/drivers/net/irda/au1000_ircc.h deleted file mode 100644 index c072c09a8d91..000000000000 --- a/drivers/net/irda/au1000_ircc.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * Au1000 IrDA driver. - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef AU1000_IRCC_H -#define AU1000_IRCC_H - -#include <linux/time.h> - -#include <linux/spinlock.h> -#include <linux/pm.h> -#include <asm/io.h> - -#define NUM_IR_IFF 1 -#define NUM_IR_DESC 64 -#define RING_SIZE_4 0x0 -#define RING_SIZE_16 0x3 -#define RING_SIZE_64 0xF -#define MAX_NUM_IR_DESC 64 -#define MAX_BUF_SIZE 2048 - -#define BPS_115200 0 -#define BPS_57600 1 -#define BPS_38400 2 -#define BPS_19200 5 -#define BPS_9600 11 -#define BPS_2400 47 - -/* Ring descriptor flags */ -#define AU_OWN (1<<7) /* tx,rx */ - -#define IR_DIS_CRC (1<<6) /* tx */ -#define IR_BAD_CRC (1<<5) /* tx */ -#define IR_NEED_PULSE (1<<4) /* tx */ -#define IR_FORCE_UNDER (1<<3) /* tx */ -#define IR_DISABLE_TX (1<<2) /* tx */ -#define IR_HW_UNDER (1<<0) /* tx */ -#define IR_TX_ERROR (IR_DIS_CRC|IR_BAD_CRC|IR_HW_UNDER) - -#define IR_PHY_ERROR (1<<6) /* rx */ -#define IR_CRC_ERROR (1<<5) /* rx */ -#define IR_MAX_LEN (1<<4) /* rx */ -#define IR_FIFO_OVER (1<<3) /* rx */ -#define IR_SIR_ERROR (1<<2) /* rx */ -#define IR_RX_ERROR (IR_PHY_ERROR|IR_CRC_ERROR| \ - IR_MAX_LEN|IR_FIFO_OVER|IR_SIR_ERROR) - -typedef struct db_dest { - struct db_dest *pnext; - volatile u32 *vaddr; - dma_addr_t dma_addr; -} db_dest_t; - - -typedef struct ring_desc { - u8 count_0; /* 7:0 */ - u8 count_1; /* 12:8 */ - u8 reserved; - u8 flags; - u8 addr_0; /* 7:0 */ - u8 addr_1; /* 15:8 */ - u8 addr_2; /* 23:16 */ - u8 addr_3; /* 31:24 */ -} ring_dest_t; - - -/* Private data for each instance */ -struct au1k_private { - - db_dest_t *pDBfree; - db_dest_t db[2*NUM_IR_DESC]; - volatile ring_dest_t *rx_ring[NUM_IR_DESC]; - volatile ring_dest_t *tx_ring[NUM_IR_DESC]; - db_dest_t *rx_db_inuse[NUM_IR_DESC]; - db_dest_t *tx_db_inuse[NUM_IR_DESC]; - u32 rx_head; - u32 tx_head; - u32 tx_tail; - u32 tx_full; - - iobuff_t rx_buff; - - struct net_device *netdev; - - struct timeval stamp; - struct timeval now; - struct qos_info qos; - struct irlap_cb *irlap; - - u8 open; - u32 speed; - u32 newspeed; - - u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */ - struct timer_list timer; - - spinlock_t lock; /* For serializing operations */ -}; -#endif /* AU1000_IRCC_H */ diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index a3d696a9456a..fc503aa5288e 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -18,104 +18,220 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. */ -#include <linux/module.h> -#include <linux/types.h> + #include <linux/init.h> -#include <linux/errno.h> +#include <linux/module.h> #include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/rtnetlink.h> #include <linux/interrupt.h> -#include <linux/pm.h> -#include <linux/bitops.h> - -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/au1000.h> -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) -#include <asm/pb1000.h> -#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) -#include <asm/db1x00.h> -#include <asm/mach-db1x00/bcsr.h> -#else -#error au1k_ir: unsupported board -#endif +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/types.h> #include <net/irda/irda.h> #include <net/irda/irmod.h> #include <net/irda/wrapper.h> #include <net/irda/irda_device.h> -#include "au1000_ircc.h" +#include <asm/mach-au1x00/au1000.h> + +/* registers */ +#define IR_RING_PTR_STATUS 0x00 +#define IR_RING_BASE_ADDR_H 0x04 +#define IR_RING_BASE_ADDR_L 0x08 +#define IR_RING_SIZE 0x0C +#define IR_RING_PROMPT 0x10 +#define IR_RING_ADDR_CMPR 0x14 +#define IR_INT_CLEAR 0x18 +#define IR_CONFIG_1 0x20 +#define IR_SIR_FLAGS 0x24 +#define IR_STATUS 0x28 +#define IR_READ_PHY_CONFIG 0x2C +#define IR_WRITE_PHY_CONFIG 0x30 +#define IR_MAX_PKT_LEN 0x34 +#define IR_RX_BYTE_CNT 0x38 +#define IR_CONFIG_2 0x3C +#define IR_ENABLE 0x40 + +/* Config1 */ +#define IR_RX_INVERT_LED (1 << 0) +#define IR_TX_INVERT_LED (1 << 1) +#define IR_ST (1 << 2) +#define IR_SF (1 << 3) +#define IR_SIR (1 << 4) +#define IR_MIR (1 << 5) +#define IR_FIR (1 << 6) +#define IR_16CRC (1 << 7) +#define IR_TD (1 << 8) +#define IR_RX_ALL (1 << 9) +#define IR_DMA_ENABLE (1 << 10) +#define IR_RX_ENABLE (1 << 11) +#define IR_TX_ENABLE (1 << 12) +#define IR_LOOPBACK (1 << 14) +#define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ + IR_RX_ALL | IR_RX_ENABLE | IR_SF | \ + IR_16CRC) + +/* ir_status */ +#define IR_RX_STATUS (1 << 9) +#define IR_TX_STATUS (1 << 10) +#define IR_PHYEN (1 << 15) + +/* ir_write_phy_config */ +#define IR_BR(x) (((x) & 0x3f) << 10) /* baud rate */ +#define IR_PW(x) (((x) & 0x1f) << 5) /* pulse width */ +#define IR_P(x) ((x) & 0x1f) /* preamble bits */ + +/* Config2 */ +#define IR_MODE_INV (1 << 0) +#define IR_ONE_PIN (1 << 1) +#define IR_PHYCLK_40MHZ (0 << 2) +#define IR_PHYCLK_48MHZ (1 << 2) +#define IR_PHYCLK_56MHZ (2 << 2) +#define IR_PHYCLK_64MHZ (3 << 2) +#define IR_DP (1 << 4) +#define IR_DA (1 << 5) +#define IR_FLT_HIGH (0 << 6) +#define IR_FLT_MEDHI (1 << 6) +#define IR_FLT_MEDLO (2 << 6) +#define IR_FLT_LO (3 << 6) +#define IR_IEN (1 << 8) + +/* ir_enable */ +#define IR_HC (1 << 3) /* divide SBUS clock by 2 */ +#define IR_CE (1 << 2) /* clock enable */ +#define IR_C (1 << 1) /* coherency bit */ +#define IR_BE (1 << 0) /* set in big endian mode */ + +#define NUM_IR_DESC 64 +#define RING_SIZE_4 0x0 +#define RING_SIZE_16 0x3 +#define RING_SIZE_64 0xF +#define MAX_NUM_IR_DESC 64 +#define MAX_BUF_SIZE 2048 + +/* Ring descriptor flags */ +#define AU_OWN (1 << 7) /* tx,rx */ +#define IR_DIS_CRC (1 << 6) /* tx */ +#define IR_BAD_CRC (1 << 5) /* tx */ +#define IR_NEED_PULSE (1 << 4) /* tx */ +#define IR_FORCE_UNDER (1 << 3) /* tx */ +#define IR_DISABLE_TX (1 << 2) /* tx */ +#define IR_HW_UNDER (1 << 0) /* tx */ +#define IR_TX_ERROR (IR_DIS_CRC | IR_BAD_CRC | IR_HW_UNDER) + +#define IR_PHY_ERROR (1 << 6) /* rx */ +#define IR_CRC_ERROR (1 << 5) /* rx */ +#define IR_MAX_LEN (1 << 4) /* rx */ +#define IR_FIFO_OVER (1 << 3) /* rx */ +#define IR_SIR_ERROR (1 << 2) /* rx */ +#define IR_RX_ERROR (IR_PHY_ERROR | IR_CRC_ERROR | \ + IR_MAX_LEN | IR_FIFO_OVER | IR_SIR_ERROR) + +struct db_dest { + struct db_dest *pnext; + volatile u32 *vaddr; + dma_addr_t dma_addr; +}; -static int au1k_irda_net_init(struct net_device *); -static int au1k_irda_start(struct net_device *); -static int au1k_irda_stop(struct net_device *dev); -static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); -static int au1k_irda_rx(struct net_device *); -static void au1k_irda_interrupt(int, void *); -static void au1k_tx_timeout(struct net_device *); -static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); -static int au1k_irda_set_speed(struct net_device *dev, int speed); +struct ring_dest { + u8 count_0; /* 7:0 */ + u8 count_1; /* 12:8 */ + u8 reserved; + u8 flags; + u8 addr_0; /* 7:0 */ + u8 addr_1; /* 15:8 */ + u8 addr_2; /* 23:16 */ + u8 addr_3; /* 31:24 */ +}; -static void *dma_alloc(size_t, dma_addr_t *); -static void dma_free(void *, size_t); +/* Private data for each instance */ +struct au1k_private { + void __iomem *iobase; + int irq_rx, irq_tx; + + struct db_dest *pDBfree; + struct db_dest db[2 * NUM_IR_DESC]; + volatile struct ring_dest *rx_ring[NUM_IR_DESC]; + volatile struct ring_dest *tx_ring[NUM_IR_DESC]; + struct db_dest *rx_db_inuse[NUM_IR_DESC]; + struct db_dest *tx_db_inuse[NUM_IR_DESC]; + u32 rx_head; + u32 tx_head; + u32 tx_tail; + u32 tx_full; + + iobuff_t rx_buff; + + struct net_device *netdev; + struct timeval stamp; + struct timeval now; + struct qos_info qos; + struct irlap_cb *irlap; + + u8 open; + u32 speed; + u32 newspeed; + + struct timer_list timer; + + struct resource *ioarea; + struct au1k_irda_platform_data *platdata; +}; static int qos_mtt_bits = 0x07; /* 1 ms or more */ -static struct net_device *ir_devs[NUM_IR_IFF]; -static char version[] __devinitdata = - "au1k_ircc:1.2 ppopov@mvista.com\n"; #define RUN_AT(x) (jiffies + (x)) -static DEFINE_SPINLOCK(ir_lock); +static void au1k_irda_plat_set_phy_mode(struct au1k_private *p, int mode) +{ + if (p->platdata && p->platdata->set_phy_mode) + p->platdata->set_phy_mode(mode); +} -/* - * IrDA peripheral bug. You have to read the register - * twice to get the right value. - */ -u32 read_ir_reg(u32 addr) -{ - readl(addr); - return readl(addr); +static inline unsigned long irda_read(struct au1k_private *p, + unsigned long ofs) +{ + /* + * IrDA peripheral bug. You have to read the register + * twice to get the right value. + */ + (void)__raw_readl(p->iobase + ofs); + return __raw_readl(p->iobase + ofs); } +static inline void irda_write(struct au1k_private *p, unsigned long ofs, + unsigned long val) +{ + __raw_writel(val, p->iobase + ofs); + wmb(); +} /* * Buffer allocation/deallocation routines. The buffer descriptor returned - * has the virtual and dma address of a buffer suitable for + * has the virtual and dma address of a buffer suitable for * both, receive and transmit operations. */ -static db_dest_t *GetFreeDB(struct au1k_private *aup) +static struct db_dest *GetFreeDB(struct au1k_private *aup) { - db_dest_t *pDB; - pDB = aup->pDBfree; - - if (pDB) { - aup->pDBfree = pDB->pnext; - } - return pDB; -} + struct db_dest *db; + db = aup->pDBfree; -static void ReleaseDB(struct au1k_private *aup, db_dest_t *pDB) -{ - db_dest_t *pDBfree = aup->pDBfree; - if (pDBfree) - pDBfree->pnext = pDB; - aup->pDBfree = pDB; + if (db) + aup->pDBfree = db->pnext; + return db; } - /* DMA memory allocation, derived from pci_alloc_consistent. However, the Au1000 data cache is coherent (when programmed so), therefore we return KSEG0 address, not KSEG1. */ -static void *dma_alloc(size_t size, dma_addr_t * dma_handle) +static void *dma_alloc(size_t size, dma_addr_t *dma_handle) { void *ret; int gfp = GFP_ATOMIC | GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { memset(ret, 0, size); @@ -125,7 +241,6 @@ static void *dma_alloc(size_t size, dma_addr_t * dma_handle) return ret; } - static void dma_free(void *vaddr, size_t size) { vaddr = (void *)KSEG0ADDR(vaddr); @@ -133,206 +248,306 @@ static void dma_free(void *vaddr, size_t size) } -static void -setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) +static void setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) { int i; - for (i=0; i<NUM_IR_DESC; i++) { - aup->rx_ring[i] = (volatile ring_dest_t *) - (rx_base + sizeof(ring_dest_t)*i); + for (i = 0; i < NUM_IR_DESC; i++) { + aup->rx_ring[i] = (volatile struct ring_dest *) + (rx_base + sizeof(struct ring_dest) * i); } - for (i=0; i<NUM_IR_DESC; i++) { - aup->tx_ring[i] = (volatile ring_dest_t *) - (tx_base + sizeof(ring_dest_t)*i); + for (i = 0; i < NUM_IR_DESC; i++) { + aup->tx_ring[i] = (volatile struct ring_dest *) + (tx_base + sizeof(struct ring_dest) * i); } } -static int au1k_irda_init(void) -{ - static unsigned version_printed = 0; - struct au1k_private *aup; - struct net_device *dev; - int err; - - if (version_printed++ == 0) printk(version); - - dev = alloc_irdadev(sizeof(struct au1k_private)); - if (!dev) - return -ENOMEM; - - dev->irq = AU1000_IRDA_RX_INT; /* TX has its own interrupt */ - err = au1k_irda_net_init(dev); - if (err) - goto out; - err = register_netdev(dev); - if (err) - goto out1; - ir_devs[0] = dev; - printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); - return 0; - -out1: - aup = netdev_priv(dev); - dma_free((void *)aup->db[0].vaddr, - MAX_BUF_SIZE * 2*NUM_IR_DESC); - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); - kfree(aup->rx_buff.head); -out: - free_netdev(dev); - return err; -} - static int au1k_irda_init_iobuf(iobuff_t *io, int size) { io->head = kmalloc(size, GFP_KERNEL); if (io->head != NULL) { - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; + io->truesize = size; + io->in_frame = FALSE; + io->state = OUTSIDE_FRAME; + io->data = io->head; } return io->head ? 0 : -ENOMEM; } -static const struct net_device_ops au1k_irda_netdev_ops = { - .ndo_open = au1k_irda_start, - .ndo_stop = au1k_irda_stop, - .ndo_start_xmit = au1k_irda_hard_xmit, - .ndo_tx_timeout = au1k_tx_timeout, - .ndo_do_ioctl = au1k_irda_ioctl, -}; - -static int au1k_irda_net_init(struct net_device *dev) +/* + * Set the IrDA communications speed. + */ +static int au1k_irda_set_speed(struct net_device *dev, int speed) { struct au1k_private *aup = netdev_priv(dev); - int i, retval = 0, err; - db_dest_t *pDB, *pDBfree; - dma_addr_t temp; + volatile struct ring_dest *ptxd; + unsigned long control; + int ret = 0, timeout = 10, i; - err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); - if (err) - goto out1; + if (speed == aup->speed) + return ret; - dev->netdev_ops = &au1k_irda_netdev_ops; + /* disable PHY first */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); - irda_init_max_qos_capabilies(&aup->qos); + /* disable RX/TX */ + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~(IR_RX_ENABLE | IR_TX_ENABLE)); + msleep(20); + while (irda_read(aup, IR_STATUS) & (IR_RX_STATUS | IR_TX_STATUS)) { + msleep(20); + if (!timeout--) { + printk(KERN_ERR "%s: rx/tx disable timeout\n", + dev->name); + break; + } + } - /* The only value we must override it the baudrate */ - aup->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000 |(IR_4000000 << 8); - - aup->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&aup->qos); + /* disable DMA */ + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~IR_DMA_ENABLE); + msleep(20); - retval = -ENOMEM; + /* After we disable tx/rx. the index pointers go back to zero. */ + aup->tx_head = aup->tx_tail = aup->rx_head = 0; + for (i = 0; i < NUM_IR_DESC; i++) { + ptxd = aup->tx_ring[i]; + ptxd->flags = 0; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + } - /* Tx ring follows rx ring + 512 bytes */ - /* we need a 1k aligned buffer */ - aup->rx_ring[0] = (ring_dest_t *) - dma_alloc(2*MAX_NUM_IR_DESC*(sizeof(ring_dest_t)), &temp); - if (!aup->rx_ring[0]) - goto out2; + for (i = 0; i < NUM_IR_DESC; i++) { + ptxd = aup->rx_ring[i]; + ptxd->count_0 = 0; + ptxd->count_1 = 0; + ptxd->flags = AU_OWN; + } - /* allocate the data buffers */ - aup->db[0].vaddr = - (void *)dma_alloc(MAX_BUF_SIZE * 2*NUM_IR_DESC, &temp); - if (!aup->db[0].vaddr) - goto out3; + if (speed == 4000000) + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_FIR); + else + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); - setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + switch (speed) { + case 9600: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(11) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 19200: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(5) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 38400: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(2) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 57600: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(1) | IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 115200: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_PW(12)); + irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); + break; + case 4000000: + irda_write(aup, IR_WRITE_PHY_CONFIG, IR_P(15)); + irda_write(aup, IR_CONFIG_1, IR_FIR | IR_DMA_ENABLE | + IR_RX_ENABLE); + break; + default: + printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); + ret = -EINVAL; + break; + } - pDBfree = NULL; - pDB = aup->db; - for (i=0; i<(2*NUM_IR_DESC); i++) { - pDB->pnext = pDBfree; - pDBfree = pDB; - pDB->vaddr = - (u32 *)((unsigned)aup->db[0].vaddr + MAX_BUF_SIZE*i); - pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); - pDB++; + aup->speed = speed; + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) | IR_PHYEN); + + control = irda_read(aup, IR_STATUS); + irda_write(aup, IR_RING_PROMPT, 0); + + if (control & (1 << 14)) { + printk(KERN_ERR "%s: configuration error\n", dev->name); + } else { + if (control & (1 << 11)) + printk(KERN_DEBUG "%s Valid SIR config\n", dev->name); + if (control & (1 << 12)) + printk(KERN_DEBUG "%s Valid MIR config\n", dev->name); + if (control & (1 << 13)) + printk(KERN_DEBUG "%s Valid FIR config\n", dev->name); + if (control & (1 << 10)) + printk(KERN_DEBUG "%s TX enabled\n", dev->name); + if (control & (1 << 9)) + printk(KERN_DEBUG "%s RX enabled\n", dev->name); } - aup->pDBfree = pDBfree; - /* attach a data buffer to each descriptor */ - for (i=0; i<NUM_IR_DESC; i++) { - pDB = GetFreeDB(aup); - if (!pDB) goto out; - aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); - aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); - aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); - aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); - aup->rx_db_inuse[i] = pDB; + return ret; +} + +static void update_rx_stats(struct net_device *dev, u32 status, u32 count) +{ + struct net_device_stats *ps = &dev->stats; + + ps->rx_packets++; + + if (status & IR_RX_ERROR) { + ps->rx_errors++; + if (status & (IR_PHY_ERROR | IR_FIFO_OVER)) + ps->rx_missed_errors++; + if (status & IR_MAX_LEN) + ps->rx_length_errors++; + if (status & IR_CRC_ERROR) + ps->rx_crc_errors++; + } else + ps->rx_bytes += count; +} + +static void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +{ + struct net_device_stats *ps = &dev->stats; + + ps->tx_packets++; + ps->tx_bytes += pkt_len; + + if (status & IR_TX_ERROR) { + ps->tx_errors++; + ps->tx_aborted_errors++; } - for (i=0; i<NUM_IR_DESC; i++) { - pDB = GetFreeDB(aup); - if (!pDB) goto out; - aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); - aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr>>8) & 0xff); - aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr>>16) & 0xff); - aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr>>24) & 0xff); - aup->tx_ring[i]->count_0 = 0; - aup->tx_ring[i]->count_1 = 0; - aup->tx_ring[i]->flags = 0; - aup->tx_db_inuse[i] = pDB; +} + +static void au1k_tx_ack(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *ptxd; + + ptxd = aup->tx_ring[aup->tx_tail]; + while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { + update_tx_stats(dev, ptxd->flags, + (ptxd->count_1 << 8) | ptxd->count_0); + ptxd->count_0 = 0; + ptxd->count_1 = 0; + wmb(); + aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); + ptxd = aup->tx_ring[aup->tx_tail]; + + if (aup->tx_full) { + aup->tx_full = 0; + netif_wake_queue(dev); + } } -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - /* power on */ - bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK, - BCSR_RESETS_IRDA_MODE_FULL); -#endif + if (aup->tx_tail == aup->tx_head) { + if (aup->newspeed) { + au1k_irda_set_speed(dev, aup->newspeed); + aup->newspeed = 0; + } else { + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) & ~IR_TX_ENABLE); + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) | IR_RX_ENABLE); + irda_write(aup, IR_RING_PROMPT, 0); + } + } +} - return 0; +static int au1k_irda_rx(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + volatile struct ring_dest *prxd; + struct sk_buff *skb; + struct db_dest *pDB; + u32 flags, count; -out3: - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); -out2: - kfree(aup->rx_buff.head); -out1: - printk(KERN_ERR "au1k_init_module failed. Returns %d\n", retval); - return retval; + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + while (!(flags & AU_OWN)) { + pDB = aup->rx_db_inuse[aup->rx_head]; + count = (prxd->count_1 << 8) | prxd->count_0; + if (!(flags & IR_RX_ERROR)) { + /* good frame */ + update_rx_stats(dev, flags, count); + skb = alloc_skb(count + 1, GFP_ATOMIC); + if (skb == NULL) { + dev->stats.rx_dropped++; + continue; + } + skb_reserve(skb, 1); + if (aup->speed == 4000000) + skb_put(skb, count); + else + skb_put(skb, count - 2); + skb_copy_to_linear_data(skb, (void *)pDB->vaddr, + count - 2); + skb->dev = dev; + skb_reset_mac_header(skb); + skb->protocol = htons(ETH_P_IRDA); + netif_rx(skb); + prxd->count_0 = 0; + prxd->count_1 = 0; + } + prxd->flags |= AU_OWN; + aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); + irda_write(aup, IR_RING_PROMPT, 0); + + /* next descriptor */ + prxd = aup->rx_ring[aup->rx_head]; + flags = prxd->flags; + + } + return 0; } +static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id) +{ + struct net_device *dev = dev_id; + struct au1k_private *aup = netdev_priv(dev); + + irda_write(aup, IR_INT_CLEAR, 0); /* ack irda interrupts */ + + au1k_irda_rx(dev); + au1k_tx_ack(dev); + + return IRQ_HANDLED; +} static int au1k_init(struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); + u32 enable, ring_address; int i; - u32 control; - u32 ring_address; - /* bring the device out of reset */ - control = 0xe; /* coherent, clock enable, one half system clock */ - + enable = IR_HC | IR_CE | IR_C; #ifndef CONFIG_CPU_LITTLE_ENDIAN - control |= 1; + enable |= IR_BE; #endif aup->tx_head = 0; aup->tx_tail = 0; aup->rx_head = 0; - for (i=0; i<NUM_IR_DESC; i++) { + for (i = 0; i < NUM_IR_DESC; i++) aup->rx_ring[i]->flags = AU_OWN; - } - writel(control, IR_INTERFACE_CONFIG); - au_sync_delay(10); + irda_write(aup, IR_ENABLE, enable); + msleep(20); - writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); /* disable PHY */ - au_sync_delay(1); + /* disable PHY */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); + msleep(20); - writel(MAX_BUF_SIZE, IR_MAX_PKT_LEN); + irda_write(aup, IR_MAX_PKT_LEN, MAX_BUF_SIZE); ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); - writel(ring_address >> 26, IR_RING_BASE_ADDR_H); - writel((ring_address >> 10) & 0xffff, IR_RING_BASE_ADDR_L); + irda_write(aup, IR_RING_BASE_ADDR_H, ring_address >> 26); + irda_write(aup, IR_RING_BASE_ADDR_L, (ring_address >> 10) & 0xffff); - writel(RING_SIZE_64<<8 | RING_SIZE_64<<12, IR_RING_SIZE); + irda_write(aup, IR_RING_SIZE, + (RING_SIZE_64 << 8) | (RING_SIZE_64 << 12)); - writel(1<<2 | IR_ONE_PIN, IR_CONFIG_2); /* 48MHz */ - writel(0, IR_RING_ADDR_CMPR); + irda_write(aup, IR_CONFIG_2, IR_PHYCLK_48MHZ | IR_ONE_PIN); + irda_write(aup, IR_RING_ADDR_CMPR, 0); au1k_irda_set_speed(dev, 9600); return 0; @@ -340,25 +555,28 @@ static int au1k_init(struct net_device *dev) static int au1k_irda_start(struct net_device *dev) { - int retval; - char hwname[32]; struct au1k_private *aup = netdev_priv(dev); + char hwname[32]; + int retval; - if ((retval = au1k_init(dev))) { + retval = au1k_init(dev); + if (retval) { printk(KERN_ERR "%s: error in au1k_init\n", dev->name); return retval; } - if ((retval = request_irq(AU1000_IRDA_TX_INT, au1k_irda_interrupt, - 0, dev->name, dev))) { - printk(KERN_ERR "%s: unable to get IRQ %d\n", + retval = request_irq(aup->irq_tx, &au1k_irda_interrupt, 0, + dev->name, dev); + if (retval) { + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); return retval; } - if ((retval = request_irq(AU1000_IRDA_RX_INT, au1k_irda_interrupt, - 0, dev->name, dev))) { - free_irq(AU1000_IRDA_TX_INT, dev); - printk(KERN_ERR "%s: unable to get IRQ %d\n", + retval = request_irq(aup->irq_rx, &au1k_irda_interrupt, 0, + dev->name, dev); + if (retval) { + free_irq(aup->irq_tx, dev); + printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, dev->irq); return retval; } @@ -368,9 +586,13 @@ static int au1k_irda_start(struct net_device *dev) aup->irlap = irlap_open(dev, &aup->qos, hwname); netif_start_queue(dev); - writel(read_ir_reg(IR_CONFIG_2) | 1<<8, IR_CONFIG_2); /* int enable */ + /* int enable */ + irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) | IR_IEN); + + /* power up */ + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); - aup->timer.expires = RUN_AT((3*HZ)); + aup->timer.expires = RUN_AT((3 * HZ)); aup->timer.data = (unsigned long)dev; return 0; } @@ -379,11 +601,12 @@ static int au1k_irda_stop(struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); + au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); + /* disable interrupts */ - writel(read_ir_reg(IR_CONFIG_2) & ~(1<<8), IR_CONFIG_2); - writel(0, IR_CONFIG_1); - writel(0, IR_INTERFACE_CONFIG); /* disable clock */ - au_sync(); + irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) & ~IR_IEN); + irda_write(aup, IR_CONFIG_1, 0); + irda_write(aup, IR_ENABLE, 0); /* disable clock */ if (aup->irlap) { irlap_close(aup->irlap); @@ -394,83 +617,12 @@ static int au1k_irda_stop(struct net_device *dev) del_timer(&aup->timer); /* disable the interrupt */ - free_irq(AU1000_IRDA_TX_INT, dev); - free_irq(AU1000_IRDA_RX_INT, dev); - return 0; -} - -static void __exit au1k_irda_exit(void) -{ - struct net_device *dev = ir_devs[0]; - struct au1k_private *aup = netdev_priv(dev); + free_irq(aup->irq_tx, dev); + free_irq(aup->irq_rx, dev); - unregister_netdev(dev); - - dma_free((void *)aup->db[0].vaddr, - MAX_BUF_SIZE * 2*NUM_IR_DESC); - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC*(sizeof(ring_dest_t))); - kfree(aup->rx_buff.head); - free_netdev(dev); -} - - -static inline void -update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) -{ - struct au1k_private *aup = netdev_priv(dev); - struct net_device_stats *ps = &aup->stats; - - ps->tx_packets++; - ps->tx_bytes += pkt_len; - - if (status & IR_TX_ERROR) { - ps->tx_errors++; - ps->tx_aborted_errors++; - } -} - - -static void au1k_tx_ack(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - volatile ring_dest_t *ptxd; - - ptxd = aup->tx_ring[aup->tx_tail]; - while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { - update_tx_stats(dev, ptxd->flags, - ptxd->count_1<<8 | ptxd->count_0); - ptxd->count_0 = 0; - ptxd->count_1 = 0; - au_sync(); - - aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); - ptxd = aup->tx_ring[aup->tx_tail]; - - if (aup->tx_full) { - aup->tx_full = 0; - netif_wake_queue(dev); - } - } - - if (aup->tx_tail == aup->tx_head) { - if (aup->newspeed) { - au1k_irda_set_speed(dev, aup->newspeed); - aup->newspeed = 0; - } - else { - writel(read_ir_reg(IR_CONFIG_1) & ~IR_TX_ENABLE, - IR_CONFIG_1); - au_sync(); - writel(read_ir_reg(IR_CONFIG_1) | IR_RX_ENABLE, - IR_CONFIG_1); - writel(0, IR_RING_PROMPT); - au_sync(); - } - } + return 0; } - /* * Au1000 transmit routine. */ @@ -478,15 +630,12 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct au1k_private *aup = netdev_priv(dev); int speed = irda_get_next_speed(skb); - volatile ring_dest_t *ptxd; - u32 len; - - u32 flags; - db_dest_t *pDB; + volatile struct ring_dest *ptxd; + struct db_dest *pDB; + u32 len, flags; - if (speed != aup->speed && speed != -1) { + if (speed != aup->speed && speed != -1) aup->newspeed = speed; - } if ((skb->len == 0) && (aup->newspeed)) { if (aup->tx_tail == aup->tx_head) { @@ -504,138 +653,47 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; - } - else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { + return 1; + } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { printk(KERN_DEBUG "%s: tx_full\n", dev->name); netif_stop_queue(dev); aup->tx_full = 1; - return NETDEV_TX_BUSY; + return 1; } pDB = aup->tx_db_inuse[aup->tx_head]; #if 0 - if (read_ir_reg(IR_RX_BYTE_CNT) != 0) { - printk("tx warning: rx byte cnt %x\n", - read_ir_reg(IR_RX_BYTE_CNT)); + if (irda_read(aup, IR_RX_BYTE_CNT) != 0) { + printk(KERN_DEBUG "tx warning: rx byte cnt %x\n", + irda_read(aup, IR_RX_BYTE_CNT)); } #endif - + if (aup->speed == 4000000) { /* FIR */ - skb_copy_from_linear_data(skb, pDB->vaddr, skb->len); + skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len); ptxd->count_0 = skb->len & 0xff; ptxd->count_1 = (skb->len >> 8) & 0xff; - - } - else { + } else { /* SIR */ len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); ptxd->count_0 = len & 0xff; ptxd->count_1 = (len >> 8) & 0xff; ptxd->flags |= IR_DIS_CRC; - au_writel(au_readl(0xae00000c) & ~(1<<13), 0xae00000c); } ptxd->flags |= AU_OWN; - au_sync(); + wmb(); - writel(read_ir_reg(IR_CONFIG_1) | IR_TX_ENABLE, IR_CONFIG_1); - writel(0, IR_RING_PROMPT); - au_sync(); + irda_write(aup, IR_CONFIG_1, + irda_read(aup, IR_CONFIG_1) | IR_TX_ENABLE); + irda_write(aup, IR_RING_PROMPT, 0); dev_kfree_skb(skb); aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); return NETDEV_TX_OK; } - -static inline void -update_rx_stats(struct net_device *dev, u32 status, u32 count) -{ - struct au1k_private *aup = netdev_priv(dev); - struct net_device_stats *ps = &aup->stats; - - ps->rx_packets++; - - if (status & IR_RX_ERROR) { - ps->rx_errors++; - if (status & (IR_PHY_ERROR|IR_FIFO_OVER)) - ps->rx_missed_errors++; - if (status & IR_MAX_LEN) - ps->rx_length_errors++; - if (status & IR_CRC_ERROR) - ps->rx_crc_errors++; - } - else - ps->rx_bytes += count; -} - -/* - * Au1000 receive routine. - */ -static int au1k_irda_rx(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - struct sk_buff *skb; - volatile ring_dest_t *prxd; - u32 flags, count; - db_dest_t *pDB; - - prxd = aup->rx_ring[aup->rx_head]; - flags = prxd->flags; - - while (!(flags & AU_OWN)) { - pDB = aup->rx_db_inuse[aup->rx_head]; - count = prxd->count_1<<8 | prxd->count_0; - if (!(flags & IR_RX_ERROR)) { - /* good frame */ - update_rx_stats(dev, flags, count); - skb=alloc_skb(count+1,GFP_ATOMIC); - if (skb == NULL) { - aup->netdev->stats.rx_dropped++; - continue; - } - skb_reserve(skb, 1); - if (aup->speed == 4000000) - skb_put(skb, count); - else - skb_put(skb, count-2); - skb_copy_to_linear_data(skb, pDB->vaddr, count - 2); - skb->dev = dev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - prxd->count_0 = 0; - prxd->count_1 = 0; - } - prxd->flags |= AU_OWN; - aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); - writel(0, IR_RING_PROMPT); - au_sync(); - - /* next descriptor */ - prxd = aup->rx_ring[aup->rx_head]; - flags = prxd->flags; - - } - return 0; -} - - -static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev = dev_id; - - writel(0, IR_INT_CLEAR); /* ack irda interrupts */ - - au1k_irda_rx(dev); - au1k_tx_ack(dev); - - return IRQ_HANDLED; -} - - /* * The Tx ring has been full longer than the watchdog timeout * value. The transmitter must be hung? @@ -653,142 +711,7 @@ static void au1k_tx_timeout(struct net_device *dev) netif_wake_queue(dev); } - -/* - * Set the IrDA communications speed. - */ -static int -au1k_irda_set_speed(struct net_device *dev, int speed) -{ - unsigned long flags; - struct au1k_private *aup = netdev_priv(dev); - u32 control; - int ret = 0, timeout = 10, i; - volatile ring_dest_t *ptxd; -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - unsigned long irda_resets; -#endif - - if (speed == aup->speed) - return ret; - - spin_lock_irqsave(&ir_lock, flags); - - /* disable PHY first */ - writel(read_ir_reg(IR_ENABLE) & ~0x8000, IR_ENABLE); - - /* disable RX/TX */ - writel(read_ir_reg(IR_CONFIG_1) & ~(IR_RX_ENABLE|IR_TX_ENABLE), - IR_CONFIG_1); - au_sync_delay(1); - while (read_ir_reg(IR_ENABLE) & (IR_RX_STATUS | IR_TX_STATUS)) { - mdelay(1); - if (!timeout--) { - printk(KERN_ERR "%s: rx/tx disable timeout\n", - dev->name); - break; - } - } - - /* disable DMA */ - writel(read_ir_reg(IR_CONFIG_1) & ~IR_DMA_ENABLE, IR_CONFIG_1); - au_sync_delay(1); - - /* - * After we disable tx/rx. the index pointers - * go back to zero. - */ - aup->tx_head = aup->tx_tail = aup->rx_head = 0; - for (i=0; i<NUM_IR_DESC; i++) { - ptxd = aup->tx_ring[i]; - ptxd->flags = 0; - ptxd->count_0 = 0; - ptxd->count_1 = 0; - } - - for (i=0; i<NUM_IR_DESC; i++) { - ptxd = aup->rx_ring[i]; - ptxd->count_0 = 0; - ptxd->count_1 = 0; - ptxd->flags = AU_OWN; - } - - if (speed == 4000000) { -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_FIR_SEL); -#else /* Pb1000 and Pb1100 */ - writel(1<<13, CPLD_AUX1); -#endif - } - else { -#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) - bcsr_mod(BCSR_RESETS, BCSR_RESETS_FIR_SEL, 0); -#else /* Pb1000 and Pb1100 */ - writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1); -#endif - } - - switch (speed) { - case 9600: - writel(11<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 19200: - writel(5<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 38400: - writel(2<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 57600: - writel(1<<10 | 12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 115200: - writel(12<<5, IR_WRITE_PHY_CONFIG); - writel(IR_SIR_MODE, IR_CONFIG_1); - break; - case 4000000: - writel(0xF, IR_WRITE_PHY_CONFIG); - writel(IR_FIR|IR_DMA_ENABLE|IR_RX_ENABLE, IR_CONFIG_1); - break; - default: - printk(KERN_ERR "%s unsupported speed %x\n", dev->name, speed); - ret = -EINVAL; - break; - } - - aup->speed = speed; - writel(read_ir_reg(IR_ENABLE) | 0x8000, IR_ENABLE); - au_sync(); - - control = read_ir_reg(IR_ENABLE); - writel(0, IR_RING_PROMPT); - au_sync(); - - if (control & (1<<14)) { - printk(KERN_ERR "%s: configuration error\n", dev->name); - } - else { - if (control & (1<<11)) - printk(KERN_DEBUG "%s Valid SIR config\n", dev->name); - if (control & (1<<12)) - printk(KERN_DEBUG "%s Valid MIR config\n", dev->name); - if (control & (1<<13)) - printk(KERN_DEBUG "%s Valid FIR config\n", dev->name); - if (control & (1<<10)) - printk(KERN_DEBUG "%s TX enabled\n", dev->name); - if (control & (1<<9)) - printk(KERN_DEBUG "%s RX enabled\n", dev->name); - } - - spin_unlock_irqrestore(&ir_lock, flags); - return ret; -} - -static int -au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) { struct if_irda_req *rq = (struct if_irda_req *)ifreq; struct au1k_private *aup = netdev_priv(dev); @@ -829,8 +752,218 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } +static const struct net_device_ops au1k_irda_netdev_ops = { + .ndo_open = au1k_irda_start, + .ndo_stop = au1k_irda_stop, + .ndo_start_xmit = au1k_irda_hard_xmit, + .ndo_tx_timeout = au1k_tx_timeout, + .ndo_do_ioctl = au1k_irda_ioctl, +}; + +static int __devinit au1k_irda_net_init(struct net_device *dev) +{ + struct au1k_private *aup = netdev_priv(dev); + struct db_dest *pDB, *pDBfree; + int i, err, retval = 0; + dma_addr_t temp; + + err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); + if (err) + goto out1; + + dev->netdev_ops = &au1k_irda_netdev_ops; + + irda_init_max_qos_capabilies(&aup->qos); + + /* The only value we must override it the baudrate */ + aup->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | + IR_57600 | IR_115200 | IR_576000 | (IR_4000000 << 8); + + aup->qos.min_turn_time.bits = qos_mtt_bits; + irda_qos_bits_to_value(&aup->qos); + + retval = -ENOMEM; + + /* Tx ring follows rx ring + 512 bytes */ + /* we need a 1k aligned buffer */ + aup->rx_ring[0] = (struct ring_dest *) + dma_alloc(2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)), + &temp); + if (!aup->rx_ring[0]) + goto out2; + + /* allocate the data buffers */ + aup->db[0].vaddr = + (void *)dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp); + if (!aup->db[0].vaddr) + goto out3; + + setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); + + pDBfree = NULL; + pDB = aup->db; + for (i = 0; i < (2 * NUM_IR_DESC); i++) { + pDB->pnext = pDBfree; + pDBfree = pDB; + pDB->vaddr = + (u32 *)((unsigned)aup->db[0].vaddr + (MAX_BUF_SIZE * i)); + pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); + pDB++; + } + aup->pDBfree = pDBfree; + + /* attach a data buffer to each descriptor */ + for (i = 0; i < NUM_IR_DESC; i++) { + pDB = GetFreeDB(aup); + if (!pDB) + goto out3; + aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); + aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); + aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); + aup->rx_db_inuse[i] = pDB; + } + for (i = 0; i < NUM_IR_DESC; i++) { + pDB = GetFreeDB(aup); + if (!pDB) + goto out3; + aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); + aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); + aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); + aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); + aup->tx_ring[i]->count_0 = 0; + aup->tx_ring[i]->count_1 = 0; + aup->tx_ring[i]->flags = 0; + aup->tx_db_inuse[i] = pDB; + } + + return 0; + +out3: + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); +out2: + kfree(aup->rx_buff.head); +out1: + printk(KERN_ERR "au1k_irda_net_init() failed. Returns %d\n", retval); + return retval; +} + +static int __devinit au1k_irda_probe(struct platform_device *pdev) +{ + struct au1k_private *aup; + struct net_device *dev; + struct resource *r; + int err; + + dev = alloc_irdadev(sizeof(struct au1k_private)); + if (!dev) + return -ENOMEM; + + aup = netdev_priv(dev); + + aup->platdata = pdev->dev.platform_data; + + err = -EINVAL; + r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!r) + goto out; + + aup->irq_tx = r->start; + + r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (!r) + goto out; + + aup->irq_rx = r->start; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + goto out; + + err = -EBUSY; + aup->ioarea = request_mem_region(r->start, r->end - r->start + 1, + pdev->name); + if (!aup->ioarea) + goto out; + + aup->iobase = ioremap_nocache(r->start, r->end - r->start + 1); + if (!aup->iobase) + goto out2; + + dev->irq = aup->irq_rx; + + err = au1k_irda_net_init(dev); + if (err) + goto out3; + err = register_netdev(dev); + if (err) + goto out4; + + platform_set_drvdata(pdev, dev); + + printk(KERN_INFO "IrDA: Registered device %s\n", dev->name); + return 0; + +out4: + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2 * NUM_IR_DESC); + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); + kfree(aup->rx_buff.head); +out3: + iounmap(aup->iobase); +out2: + release_resource(aup->ioarea); + kfree(aup->ioarea); +out: + free_netdev(dev); + return err; +} + +static int __devexit au1k_irda_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct au1k_private *aup = netdev_priv(dev); + + unregister_netdev(dev); + + dma_free((void *)aup->db[0].vaddr, + MAX_BUF_SIZE * 2 * NUM_IR_DESC); + dma_free((void *)aup->rx_ring[0], + 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); + kfree(aup->rx_buff.head); + + iounmap(aup->iobase); + release_resource(aup->ioarea); + kfree(aup->ioarea); + + free_netdev(dev); + + return 0; +} + +static struct platform_driver au1k_irda_driver = { + .driver = { + .name = "au1000-irda", + .owner = THIS_MODULE, + }, + .probe = au1k_irda_probe, + .remove = __devexit_p(au1k_irda_remove), +}; + +static int __init au1k_irda_load(void) +{ + return platform_driver_register(&au1k_irda_driver); +} + +static void __exit au1k_irda_unload(void) +{ + return platform_driver_unregister(&au1k_irda_driver); +} + MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); -module_init(au1k_irda_init); -module_exit(au1k_irda_exit); +module_init(au1k_irda_load); +module_exit(au1k_irda_unload); diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 9663e0ba6003..ba3c59147aa7 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1159,7 +1159,7 @@ static void rx_timestamp_work(struct work_struct *work) } } spin_unlock_irqrestore(&dp83640->rx_lock, flags); - netif_rx(skb); + netif_rx_ni(skb); } /* Clear out expired time stamps. */ diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 1fa4d73c3cca..633680d0828e 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -220,7 +220,7 @@ static int __init fixed_mdio_bus_init(void) goto err_mdiobus_reg; } - snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "0"); + snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0"); fmb->mii_bus->name = "Fixed MDIO Bus"; fmb->mii_bus->priv = fmb; fmb->mii_bus->parent = &pdev->dev; diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 89c5a3eccc12..50e8e5e74465 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -116,7 +116,7 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev, if (!new_bus->irq[i]) new_bus->irq[i] = PHY_POLL; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); if (gpio_request(bitbang->mdc, "mdc")) goto out_free_bus; diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index bd12ba941be5..826d961f39f7 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -118,7 +118,8 @@ static int __devinit octeon_mdiobus_probe(struct platform_device *pdev) bus->mii_bus->priv = bus; bus->mii_bus->irq = bus->phy_irq; bus->mii_bus->name = "mdio-octeon"; - snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit); + snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + bus->mii_bus->name, bus->unit); bus->mii_bus->parent = &pdev->dev; bus->mii_bus->read = octeon_mdiobus_read; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 6c58da2b882c..88cc5db9affd 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -37,22 +37,36 @@ #include <asm/uaccess.h> /** - * mdiobus_alloc - allocate a mii_bus structure + * mdiobus_alloc_size - allocate a mii_bus structure * * Description: called by a bus driver to allocate an mii_bus * structure to fill in. + * + * 'size' is an an extra amount of memory to allocate for private storage. + * If non-zero, then bus->priv is points to that memory. */ -struct mii_bus *mdiobus_alloc(void) +struct mii_bus *mdiobus_alloc_size(size_t size) { struct mii_bus *bus; + size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN); + size_t alloc_size; + + /* If we alloc extra space, it should be aligned */ + if (size) + alloc_size = aligned_size + size; + else + alloc_size = sizeof(*bus); - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (bus != NULL) + bus = kzalloc(alloc_size, GFP_KERNEL); + if (bus) { bus->state = MDIOBUS_ALLOCATED; + if (size) + bus->priv = (void *)bus + aligned_size; + } return bus; } -EXPORT_SYMBOL(mdiobus_alloc); +EXPORT_SYMBOL(mdiobus_alloc_size); /** * mdiobus_release - mii_bus device release callback diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index c1c9293c2bbf..df884dde2a51 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -585,8 +585,8 @@ static int pptp_create(struct net *net, struct socket *sock) po = pppox_sk(sk); opt = &po->proto.pptp; - opt->seq_sent = 0; opt->seq_recv = 0; - opt->ack_recv = 0; opt->ack_sent = 0; + opt->seq_sent = 0; opt->seq_recv = 0xffffffff; + opt->ack_recv = 0; opt->ack_sent = 0xffffffff; error = 0; out: diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index d0937c4634c9..8e84f5bdd6ca 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -978,6 +978,7 @@ static int ax88772_link_reset(struct usbnet *dev) static int ax88772_reset(struct usbnet *dev) { + struct asix_data *data = (struct asix_data *)&dev->data; int ret, embd_phy; u16 rx_ctl; @@ -1055,6 +1056,13 @@ static int ax88772_reset(struct usbnet *dev) goto out; } + /* Rewrite MAC address */ + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); + ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + if (ret < 0) + goto out; + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); if (ret < 0) @@ -1320,6 +1328,13 @@ static int ax88178_reset(struct usbnet *dev) if (ret < 0) return ret; + /* Rewrite MAC address */ + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); + ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + if (ret < 0) + return ret; + ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); if (ret < 0) return ret; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 2589b38b689a..2b0bfb8cca02 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -46,7 +46,7 @@ static const int m2ThreshExt_off = 127; * @chan: * * This is the function to change channel on single-chip devices, that is - * all devices after ar9280. + * for AR9300 family of chipsets. * * This function takes the channel value in MHz and sets * hardware channel value. Assumes writes have been enabled to analog bus. diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index b30e9fc6433f..171ccf7c972f 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -679,7 +679,6 @@ void ath9k_deinit_device(struct ath_softc *sc); void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw); void ath9k_reload_chainmask_settings(struct ath_softc *sc); -void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_uses_beacons(int type); #ifdef CONFIG_ATH9K_PCI diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 172e33db7f4c..2f4b48e6fb03 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -400,6 +400,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) ah->noise = ath9k_hw_getchan_noise(ah, chan); return true; } +EXPORT_SYMBOL(ath9k_hw_getnf); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan) diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 05b9dbf81850..3b33996d97df 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -19,7 +19,6 @@ #include "hw.h" -#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 #define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 #define NUM_NF_READINGS 6 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index e267c92dbfb8..4a00806e2852 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1629,7 +1629,6 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; - struct ath9k_channel old_chan; int pos = curchan->hw_value; int old_pos = -1; unsigned long flags; @@ -1654,11 +1653,8 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) * Preserve the current channel values, before updating * the same channel */ - if (old_pos == pos) { - memcpy(&old_chan, &sc->sc_ah->channels[pos], - sizeof(struct ath9k_channel)); - ah->curchan = &old_chan; - } + if (ah->curchan && (old_pos == pos)) + ath9k_hw_getnf(ah, ah->curchan); ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], curchan, conf->channel_type); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 5a002a21f108..f7eeee1dcdb6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -3119,8 +3119,10 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) /* Verify NVRAM bytes */ brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); nvram_ularray = kmalloc(varsize, GFP_ATOMIC); - if (!nvram_ularray) + if (!nvram_ularray) { + kfree(vbuffer); return -ENOMEM; + } /* Upload image to verify downloaded contents. */ memset(nvram_ularray, 0xaa, varsize); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c index 6f91a148c222..3fda6b1dcf46 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -196,6 +196,8 @@ static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, /* Allocate skb buffer to contain firmware */ /* info and tx descriptor info. */ skb = dev_alloc_skb(frag_length); + if (!skb) + return false; skb_reserve(skb, extra_descoffset); seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - extra_descoffset)); @@ -573,6 +575,8 @@ static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); skb = dev_alloc_skb(len); + if (!skb) + return false; cb_desc = (struct rtl_tcb_desc *)(skb->cb); cb_desc->queue_index = TXCMD_QUEUE; cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; diff --git a/drivers/of/address.c b/drivers/of/address.c index 72c33fbe451d..66d96f14c274 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -14,7 +14,7 @@ static struct of_bus *of_match_bus(struct device_node *np); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, - struct resource *r); + const char *name, struct resource *r); /* Debug utility */ #ifdef DEBUG @@ -215,7 +215,7 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, addrp = of_get_pci_address(dev, bar, &size, &flags); if (addrp == NULL) return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); + return __of_address_to_resource(dev, addrp, size, flags, NULL, r); } EXPORT_SYMBOL_GPL(of_pci_address_to_resource); #endif /* CONFIG_PCI */ @@ -529,7 +529,7 @@ EXPORT_SYMBOL(of_get_address); static int __of_address_to_resource(struct device_node *dev, const __be32 *addrp, u64 size, unsigned int flags, - struct resource *r) + const char *name, struct resource *r) { u64 taddr; @@ -551,7 +551,8 @@ static int __of_address_to_resource(struct device_node *dev, r->end = taddr + size - 1; } r->flags = flags; - r->name = dev->full_name; + r->name = name ? name : dev->full_name; + return 0; } @@ -569,11 +570,16 @@ int of_address_to_resource(struct device_node *dev, int index, const __be32 *addrp; u64 size; unsigned int flags; + const char *name = NULL; addrp = of_get_address(dev, index, &size, &flags); if (addrp == NULL) return -EINVAL; - return __of_address_to_resource(dev, addrp, size, flags, r); + + /* Get optional "reg-names" property to add a name to a resource */ + of_property_read_string_index(dev, "reg-names", index, &name); + + return __of_address_to_resource(dev, addrp, size, flags, name, r); } EXPORT_SYMBOL_GPL(of_address_to_resource); diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 0f0cfa3bca30..9cf00602f566 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -341,9 +341,18 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) /* Only dereference the resource if both the * resource and the irq are valid. */ if (r && irq) { + const char *name = NULL; + + /* + * Get optional "interrupts-names" property to add a name + * to the resource. + */ + of_property_read_string_index(dev, "interrupt-names", index, + &name); + r->start = r->end = irq; r->flags = IORESOURCE_IRQ; - r->name = dev->full_name; + r->name = name ? name : dev->full_name; } return irq; diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c index 0dc34f12f92e..d4716273651e 100644 --- a/drivers/parport/parport_ip32.c +++ b/drivers/parport/parport_ip32.c @@ -135,7 +135,7 @@ #define PARPORT_IP32_ENABLE_EPP (1U << 3) #define PARPORT_IP32_ENABLE_ECP (1U << 4) static unsigned int features = ~0U; -static int verbose_probing = DEFAULT_VERBOSE_PROBING; +static bool verbose_probing = DEFAULT_VERBOSE_PROBING; /* We do not support more than one port. */ static struct parport *this_port = NULL; diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index d0b597b50398..0cb64f50cecd 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -3404,8 +3404,8 @@ static int __init parport_init_mode_setup(char *str) #endif #ifdef MODULE -static const char *irq[PARPORT_PC_MAX_PORTS]; -static const char *dma[PARPORT_PC_MAX_PORTS]; +static char *irq[PARPORT_PC_MAX_PORTS]; +static char *dma[PARPORT_PC_MAX_PORTS]; MODULE_PARM_DESC(io, "Base I/O address (SPP regs)"); module_param_array(io, int, NULL, 0); diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 095f29e13734..2a47e82821da 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -44,7 +44,7 @@ #define METHOD_NAME__SUN "_SUN" #define METHOD_NAME_OSHP "OSHP" -static int debug_acpi; +static bool debug_acpi; static acpi_status decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx) diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index efa9f2de51c1..aa41631e9e02 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -47,7 +47,7 @@ /* name size which is used for entries in pcihpfs */ #define SLOT_NAME_SIZE 21 /* {_SUN} */ -static int debug; +static bool debug; int acpiphp_debug; /* local variables */ diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index e525263210ee..c35e8ad6db01 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -43,7 +43,7 @@ #define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension" -static int debug; +static bool debug; MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index 41f6a8d79c81..6bf8d2ab164f 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -57,8 +57,8 @@ #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static int debug; -static int poll; +static bool debug; +static bool poll; static struct cpci_hp_controller_ops zt5550_hpc_ops; static struct cpci_hp_controller zt5550_hpc; diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index f1ce99cceac6..187a199da93c 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -57,8 +57,8 @@ struct irq_routing_table *cpqhp_routing_table; static void __iomem *smbios_table; static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; -static int power_mode; -static int debug; +static bool power_mode; +static bool debug; static int initialized; #define DRIVER_VERSION "0.9.8" diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c index d934dd4fa873..5506e0e8fbc0 100644 --- a/drivers/pci/hotplug/ibmphp_core.c +++ b/drivers/pci/hotplug/ibmphp_core.c @@ -49,7 +49,7 @@ int ibmphp_debug; -static int debug; +static bool debug; module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); MODULE_LICENSE ("GPL"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 6d2eea93298f..202f4a969eb5 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -51,7 +51,7 @@ /* local variables */ -static int debug; +static bool debug; #define DRIVER_VERSION "0.5" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 9a33fdde2d16..4b7cce1de6ec 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -40,10 +40,10 @@ #define MY_NAME "pciehp" -extern int pciehp_poll_mode; +extern bool pciehp_poll_mode; extern int pciehp_poll_time; -extern int pciehp_debug; -extern int pciehp_force; +extern bool pciehp_debug; +extern bool pciehp_force; extern struct workqueue_struct *pciehp_wq; #define dbg(format, arg...) \ diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index b8c99d35ac97..365c6b96c642 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -38,10 +38,10 @@ #include <linux/time.h> /* Global variables */ -int pciehp_debug; -int pciehp_poll_mode; +bool pciehp_debug; +bool pciehp_poll_mode; int pciehp_poll_time; -int pciehp_force; +bool pciehp_force; struct workqueue_struct *pciehp_wq; #define DRIVER_VERSION "0.4" diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c index 5175d9b26f0b..b20ceaaa31f4 100644 --- a/drivers/pci/hotplug/pcihp_skeleton.c +++ b/drivers/pci/hotplug/pcihp_skeleton.c @@ -59,7 +59,7 @@ static LIST_HEAD(slot_list); #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) /* local variables */ -static int debug; +static bool debug; static int num_slots; #define DRIVER_VERSION "0.3" diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h index 419919a87b0f..df5677440a08 100644 --- a/drivers/pci/hotplug/rpaphp.h +++ b/drivers/pci/hotplug/rpaphp.h @@ -46,7 +46,7 @@ #define PRESENT 1 /* Card in slot */ #define MY_NAME "rpaphp" -extern int rpaphp_debug; +extern bool rpaphp_debug; #define dbg(format, arg...) \ do { \ if (rpaphp_debug) \ diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 758adb5f47fd..127d6e600185 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -37,7 +37,7 @@ /* and pci_do_scan_bus */ #include "rpaphp.h" -int rpaphp_debug; +bool rpaphp_debug; LIST_HEAD(rpaphp_slot_head); #define DRIVER_VERSION "0.1" diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index e0c90e643b5f..ca64932e658b 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -43,9 +43,9 @@ #define MY_NAME THIS_MODULE->name #endif -extern int shpchp_poll_mode; +extern bool shpchp_poll_mode; extern int shpchp_poll_time; -extern int shpchp_debug; +extern bool shpchp_debug; extern struct workqueue_struct *shpchp_wq; extern struct workqueue_struct *shpchp_ordered_wq; diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index dd7e0c51a33e..7414fd9ad1d2 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -36,8 +36,8 @@ #include "shpchp.h" /* Global variables */ -int shpchp_debug; -int shpchp_poll_mode; +bool shpchp_debug; +bool shpchp_poll_mode; int shpchp_poll_time; struct workqueue_struct *shpchp_wq; struct workqueue_struct *shpchp_ordered_wq; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 106be0d08f81..a3cd8cad532a 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -432,7 +432,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ - if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) { + if (security_capable(filp->f_cred, &init_user_ns, CAP_SYS_ADMIN) == 0) { size = dev->cfg_size; } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { size = 128; diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c index 95489cd9a555..52229863e9fe 100644 --- a/drivers/pci/pcie/aer/aer_inject.c +++ b/drivers/pci/pcie/aer/aer_inject.c @@ -28,7 +28,7 @@ #include "aerdrv.h" /* Override the existing corrected and uncorrected error masks */ -static int aer_mask_override; +static bool aer_mask_override; module_param(aer_mask_override, bool, 0); struct aer_error_inj { diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 9674e9f30d49..0ca053538146 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -27,8 +27,8 @@ #include <linux/kfifo.h> #include "aerdrv.h" -static int forceload; -static int nosourceid; +static bool forceload; +static bool nosourceid; module_param(forceload, bool, 0); module_param(nosourceid, bool, 0); diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 6e318ce41136..f9e3fb3a285b 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -155,18 +155,14 @@ config PCMCIA_M8XX This driver is also available as a module called m8xx_pcmcia. -config PCMCIA_AU1X00 - tristate "Au1x00 pcmcia support" - depends on MIPS_ALCHEMY && PCMCIA - config PCMCIA_ALCHEMY_DEVBOARD tristate "Alchemy Db/Pb1xxx PCMCIA socket services" depends on MIPS_ALCHEMY && PCMCIA select 64BIT_PHYS_ADDR help Enable this driver of you want PCMCIA support on your Alchemy - Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board. - NOT suitable for the PB1000! + Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200, DB1300 + board. NOT suitable for the PB1000! This driver is also available as a module called db1xxx_ss.ko diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 29935ea921df..ec543a4ff2e4 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_base.o sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_base.o sa1111_cs.o obj-$(CONFIG_M32R_PCC) += m32r_pcc.o obj-$(CONFIG_M32R_CFC) += m32r_cfc.o -obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_BCM63XX) += bcm63xx_pcmcia.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o @@ -39,9 +38,6 @@ obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o -au1x00_ss-y += au1000_generic.o -au1x00_ss-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o - sa1111_cs-y += sa1111_generic.o sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_cs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c deleted file mode 100644 index 95dd7c62741f..000000000000 --- a/drivers/pcmcia/au1000_generic.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * - * Alchemy Semi Au1000 pcmcia driver - * - * Copyright 2001-2003 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@embeddedalley.com or source@mvista.com - * - * Copyright 2004 Pete Popov, Embedded Alley Solutions, Inc. - * Updated the driver to 2.6. Followed the sa11xx API and largely - * copied many of the hardware independent functions. - * - * ######################################################################## - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * ######################################################################## - * - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/cpufreq.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/notifier.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> - -#include <asm/mach-au1x00/au1000.h> -#include "au1000_generic.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Pete Popov <ppopov@embeddedalley.com>"); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller"); - -#if 0 -#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args) -#else -#define debug(x,args...) -#endif - -#define MAP_SIZE 0x100000 -extern struct au1000_pcmcia_socket au1000_pcmcia_socket[]; -#define PCMCIA_SOCKET(x) (au1000_pcmcia_socket + (x)) -#define to_au1000_socket(x) container_of(x, struct au1000_pcmcia_socket, socket) - -/* Some boards like to support CF cards as IDE root devices, so they - * grab pcmcia sockets directly. - */ -u32 *pcmcia_base_vaddrs[2]; -extern const unsigned long mips_io_port_base; - -static DEFINE_MUTEX(pcmcia_sockets_lock); - -static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = { - au1x_board_init, -}; - -static int -au1x00_pcmcia_skt_state(struct au1000_pcmcia_socket *skt) -{ - struct pcmcia_state state; - unsigned int stat; - - memset(&state, 0, sizeof(struct pcmcia_state)); - - skt->ops->socket_state(skt, &state); - - stat = state.detect ? SS_DETECT : 0; - stat |= state.ready ? SS_READY : 0; - stat |= state.wrprot ? SS_WRPROT : 0; - stat |= state.vs_3v ? SS_3VCARD : 0; - stat |= state.vs_Xv ? SS_XVCARD : 0; - stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - - if (skt->cs_state.flags & SS_IOCARD) - stat |= state.bvd1 ? SS_STSCHG : 0; - else { - if (state.bvd1 == 0) - stat |= SS_BATDEAD; - else if (state.bvd2 == 0) - stat |= SS_BATWARN; - } - return stat; -} - -/* - * au100_pcmcia_config_skt - * - * Convert PCMCIA socket state to our socket configure structure. - */ -static int -au1x00_pcmcia_config_skt(struct au1000_pcmcia_socket *skt, socket_state_t *state) -{ - int ret; - - ret = skt->ops->configure_socket(skt, state); - if (ret == 0) { - skt->cs_state = *state; - } - - if (ret < 0) - debug("unable to configure socket %d\n", skt->nr); - - return ret; -} - -/* au1x00_pcmcia_sock_init() - * - * (Re-)Initialise the socket, turning on status interrupts - * and PCMCIA bus. This must wait for power to stabilise - * so that the card status signals report correctly. - * - * Returns: 0 - */ -static int au1x00_pcmcia_sock_init(struct pcmcia_socket *sock) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - debug("initializing socket %u\n", skt->nr); - - skt->ops->socket_init(skt); - return 0; -} - -/* - * au1x00_pcmcia_suspend() - * - * Remove power on the socket, disable IRQs from the card. - * Turn off status interrupts, and disable the PCMCIA bus. - * - * Returns: 0 - */ -static int au1x00_pcmcia_suspend(struct pcmcia_socket *sock) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - debug("suspending socket %u\n", skt->nr); - - skt->ops->socket_suspend(skt); - - return 0; -} - -static DEFINE_SPINLOCK(status_lock); - -/* - * au1x00_check_status() - */ -static void au1x00_check_status(struct au1000_pcmcia_socket *skt) -{ - unsigned int events; - - debug("entering PCMCIA monitoring thread\n"); - - do { - unsigned int status; - unsigned long flags; - - status = au1x00_pcmcia_skt_state(skt); - - spin_lock_irqsave(&status_lock, flags); - events = (status ^ skt->status) & skt->cs_state.csc_mask; - skt->status = status; - spin_unlock_irqrestore(&status_lock, flags); - - debug("events: %s%s%s%s%s%s\n", - events == 0 ? "<NONE>" : "", - events & SS_DETECT ? "DETECT " : "", - events & SS_READY ? "READY " : "", - events & SS_BATDEAD ? "BATDEAD " : "", - events & SS_BATWARN ? "BATWARN " : "", - events & SS_STSCHG ? "STSCHG " : ""); - - if (events) - pcmcia_parse_events(&skt->socket, events); - } while (events); -} - -/* - * au1x00_pcmcia_poll_event() - * Let's poll for events in addition to IRQs since IRQ only is unreliable... - */ -static void au1x00_pcmcia_poll_event(unsigned long dummy) -{ - struct au1000_pcmcia_socket *skt = (struct au1000_pcmcia_socket *)dummy; - debug("polling for events\n"); - - mod_timer(&skt->poll_timer, jiffies + AU1000_PCMCIA_POLL_PERIOD); - - au1x00_check_status(skt); -} - -/* au1x00_pcmcia_get_status() - * - * From the sa11xx_core.c: - * Implements the get_status() operation for the in-kernel PCMCIA - * service (formerly SS_GetStatus in Card Services). Essentially just - * fills in bits in `status' according to internal driver state or - * the value of the voltage detect chipselect register. - * - * As a debugging note, during card startup, the PCMCIA core issues - * three set_socket() commands in a row the first with RESET deasserted, - * the second with RESET asserted, and the last with RESET deasserted - * again. Following the third set_socket(), a get_status() command will - * be issued. The kernel is looking for the SS_READY flag (see - * setup_socket(), reset_socket(), and unreset_socket() in cs.c). - * - * Returns: 0 - */ -static int -au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - skt->status = au1x00_pcmcia_skt_state(skt); - *status = skt->status; - - return 0; -} - -/* au1x00_pcmcia_set_socket() - * Implements the set_socket() operation for the in-kernel PCMCIA - * service (formerly SS_SetSocket in Card Services). We more or - * less punt all of this work and let the kernel handle the details - * of power configuration, reset, &c. We also record the value of - * `state' in order to regurgitate it to the PCMCIA core later. - * - * Returns: 0 - */ -static int -au1x00_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - - debug("for sock %u\n", skt->nr); - - debug("\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", - (state->csc_mask==0)?"<NONE>":"", - (state->csc_mask&SS_DETECT)?"DETECT ":"", - (state->csc_mask&SS_READY)?"READY ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?"<NONE>":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); - debug("\tVcc %d Vpp %d irq %d\n", - state->Vcc, state->Vpp, state->io_irq); - - return au1x00_pcmcia_config_skt(skt, state); -} - -int -au1x00_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - unsigned int speed; - - if(map->map>=MAX_IO_WIN){ - debug("map (%d) out of range\n", map->map); - return -1; - } - - if(map->flags&MAP_ACTIVE){ - speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED; - skt->spd_io[map->map] = speed; - } - - map->start=(unsigned int)(u32)skt->virt_io; - map->stop=map->start+MAP_SIZE; - return 0; - -} /* au1x00_pcmcia_set_io_map() */ - - -static int -au1x00_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) -{ - struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); - unsigned short speed = map->speed; - - if(map->map>=MAX_WIN){ - debug("map (%d) out of range\n", map->map); - return -1; - } - - if (map->flags & MAP_ATTRIB) { - skt->spd_attr[map->map] = speed; - skt->spd_mem[map->map] = 0; - } else { - skt->spd_attr[map->map] = 0; - skt->spd_mem[map->map] = speed; - } - - if (map->flags & MAP_ATTRIB) { - map->static_start = skt->phys_attr + map->card_start; - } - else { - map->static_start = skt->phys_mem + map->card_start; - } - - debug("set_mem_map %d start %08lx card_start %08x\n", - map->map, map->static_start, map->card_start); - return 0; - -} /* au1x00_pcmcia_set_mem_map() */ - -static struct pccard_operations au1x00_pcmcia_operations = { - .init = au1x00_pcmcia_sock_init, - .suspend = au1x00_pcmcia_suspend, - .get_status = au1x00_pcmcia_get_status, - .set_socket = au1x00_pcmcia_set_socket, - .set_io_map = au1x00_pcmcia_set_io_map, - .set_mem_map = au1x00_pcmcia_set_mem_map, -}; - -static const char *skt_names[] = { - "PCMCIA socket 0", - "PCMCIA socket 1", -}; - -struct skt_dev_info { - int nskt; -}; - -int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) -{ - struct skt_dev_info *sinfo; - struct au1000_pcmcia_socket *skt; - int ret, i; - - sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL); - if (!sinfo) { - ret = -ENOMEM; - goto out; - } - - sinfo->nskt = nr; - - /* - * Initialise the per-socket structure. - */ - for (i = 0; i < nr; i++) { - skt = PCMCIA_SOCKET(i); - memset(skt, 0, sizeof(*skt)); - - skt->socket.resource_ops = &pccard_static_ops; - skt->socket.ops = &au1x00_pcmcia_operations; - skt->socket.owner = ops->owner; - skt->socket.dev.parent = dev; - - init_timer(&skt->poll_timer); - skt->poll_timer.function = au1x00_pcmcia_poll_event; - skt->poll_timer.data = (unsigned long)skt; - skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; - - skt->nr = first + i; - skt->irq = 255; - skt->dev = dev; - skt->ops = ops; - - skt->res_skt.name = skt_names[skt->nr]; - skt->res_io.name = "io"; - skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; - skt->res_mem.name = "memory"; - skt->res_mem.flags = IORESOURCE_MEM; - skt->res_attr.name = "attribute"; - skt->res_attr.flags = IORESOURCE_MEM; - - /* - * PCMCIA client drivers use the inb/outb macros to access the - * IO registers. Since mips_io_port_base is added to the - * access address of the mips implementation of inb/outb, - * we need to subtract it here because we want to access the - * I/O or MEM address directly, without going through this - * "mips_io_port_base" mechanism. - */ - if (i == 0) { - skt->virt_io = (void *) - (ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) - - (u32)mips_io_port_base); - skt->phys_attr = AU1X_SOCK0_PHYS_ATTR; - skt->phys_mem = AU1X_SOCK0_PHYS_MEM; - } - else { - skt->virt_io = (void *) - (ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) - - (u32)mips_io_port_base); - skt->phys_attr = AU1X_SOCK1_PHYS_ATTR; - skt->phys_mem = AU1X_SOCK1_PHYS_MEM; - } - pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io; - ret = ops->hw_init(skt); - - skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; - skt->socket.irq_mask = 0; - skt->socket.map_size = MAP_SIZE; - skt->socket.pci_irq = skt->irq; - skt->socket.io_offset = (unsigned long)skt->virt_io; - - skt->status = au1x00_pcmcia_skt_state(skt); - - ret = pcmcia_register_socket(&skt->socket); - if (ret) - goto out_err; - - WARN_ON(skt->socket.sock != i); - - add_timer(&skt->poll_timer); - } - - dev_set_drvdata(dev, sinfo); - return 0; - - -out_err: - ops->hw_shutdown(skt); - while (i-- > 0) { - skt = PCMCIA_SOCKET(i); - - del_timer_sync(&skt->poll_timer); - pcmcia_unregister_socket(&skt->socket); - if (i == 0) { - iounmap(skt->virt_io + (u32)mips_io_port_base); - skt->virt_io = NULL; - } -#ifndef CONFIG_MIPS_XXS1500 - else { - iounmap(skt->virt_io + (u32)mips_io_port_base); - skt->virt_io = NULL; - } -#endif - ops->hw_shutdown(skt); - - } - kfree(sinfo); -out: - return ret; -} - -int au1x00_drv_pcmcia_remove(struct platform_device *dev) -{ - struct skt_dev_info *sinfo = platform_get_drvdata(dev); - int i; - - mutex_lock(&pcmcia_sockets_lock); - platform_set_drvdata(dev, NULL); - - for (i = 0; i < sinfo->nskt; i++) { - struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - del_timer_sync(&skt->poll_timer); - pcmcia_unregister_socket(&skt->socket); - skt->ops->hw_shutdown(skt); - au1x00_pcmcia_config_skt(skt, &dead_socket); - iounmap(skt->virt_io + (u32)mips_io_port_base); - skt->virt_io = NULL; - } - - kfree(sinfo); - mutex_unlock(&pcmcia_sockets_lock); - return 0; -} - - -/* - * PCMCIA "Driver" API - */ - -static int au1x00_drv_pcmcia_probe(struct platform_device *dev) -{ - int i, ret = -ENODEV; - - mutex_lock(&pcmcia_sockets_lock); - for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) { - ret = au1x00_pcmcia_hw_init[i](&dev->dev); - if (ret == 0) - break; - } - mutex_unlock(&pcmcia_sockets_lock); - return ret; -} - -static struct platform_driver au1x00_pcmcia_driver = { - .driver = { - .name = "au1x00-pcmcia", - .owner = THIS_MODULE, - }, - .probe = au1x00_drv_pcmcia_probe, - .remove = au1x00_drv_pcmcia_remove, -}; - - -/* au1x00_pcmcia_init() - * - * This routine performs low-level PCMCIA initialization and then - * registers this socket driver with Card Services. - * - * Returns: 0 on success, -ve error code on failure - */ -static int __init au1x00_pcmcia_init(void) -{ - int error = 0; - error = platform_driver_register(&au1x00_pcmcia_driver); - return error; -} - -/* au1x00_pcmcia_exit() - * Invokes the low-level kernel service to free IRQs associated with this - * socket controller and reset GPIO edge detection. - */ -static void __exit au1x00_pcmcia_exit(void) -{ - platform_driver_unregister(&au1x00_pcmcia_driver); -} - -module_init(au1x00_pcmcia_init); -module_exit(au1x00_pcmcia_exit); diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h deleted file mode 100644 index 5c36bda2963b..000000000000 --- a/drivers/pcmcia/au1000_generic.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Alchemy Semi Au1000 pcmcia driver include file - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - */ -#ifndef __ASM_AU1000_PCMCIA_H -#define __ASM_AU1000_PCMCIA_H - -/* include the world */ - -#include <pcmcia/ss.h> -#include <pcmcia/cistpl.h> -#include "cs_internal.h" - -#define AU1000_PCMCIA_POLL_PERIOD (2*HZ) -#define AU1000_PCMCIA_IO_SPEED (255) -#define AU1000_PCMCIA_MEM_SPEED (300) - -#define AU1X_SOCK0_IO 0xF00000000ULL -#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL -#define AU1X_SOCK0_PHYS_MEM 0xF80000000ULL - -/* pcmcia socket 1 needs external glue logic so the memory map - * differs from board to board. - */ -#if defined(CONFIG_MIPS_PB1000) -#define AU1X_SOCK1_IO 0xF08000000ULL -#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL -#define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL -#endif - -struct pcmcia_state { - unsigned detect: 1, - ready: 1, - wrprot: 1, - bvd1: 1, - bvd2: 1, - vs_3v: 1, - vs_Xv: 1; -}; - -struct pcmcia_configure { - unsigned sock: 8, - vcc: 8, - vpp: 8, - output: 1, - speaker: 1, - reset: 1; -}; - -struct pcmcia_irqs { - int sock; - int irq; - const char *str; -}; - - -struct au1000_pcmcia_socket { - struct pcmcia_socket socket; - - /* - * Info from low level handler - */ - struct device *dev; - unsigned int nr; - unsigned int irq; - - /* - * Core PCMCIA state - */ - struct pcmcia_low_level *ops; - - unsigned int status; - socket_state_t cs_state; - - unsigned short spd_io[MAX_IO_WIN]; - unsigned short spd_mem[MAX_WIN]; - unsigned short spd_attr[MAX_WIN]; - - struct resource res_skt; - struct resource res_io; - struct resource res_mem; - struct resource res_attr; - - void * virt_io; - unsigned int phys_io; - unsigned int phys_attr; - unsigned int phys_mem; - unsigned short speed_io, speed_attr, speed_mem; - - unsigned int irq_state; - - struct timer_list poll_timer; -}; - -struct pcmcia_low_level { - struct module *owner; - - int (*hw_init)(struct au1000_pcmcia_socket *); - void (*hw_shutdown)(struct au1000_pcmcia_socket *); - - void (*socket_state)(struct au1000_pcmcia_socket *, struct pcmcia_state *); - int (*configure_socket)(struct au1000_pcmcia_socket *, struct socket_state_t *); - - /* - * Enable card status IRQs on (re-)initialisation. This can - * be called at initialisation, power management event, or - * pcmcia event. - */ - void (*socket_init)(struct au1000_pcmcia_socket *); - - /* - * Disable card status IRQs and PCMCIA bus on suspend. - */ - void (*socket_suspend)(struct au1000_pcmcia_socket *); -}; - -extern int au1x_board_init(struct device *dev); - -#endif /* __ASM_AU1000_PCMCIA_H */ diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c deleted file mode 100644 index b2396647a165..000000000000 --- a/drivers/pcmcia/au1000_pb1x00.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * - * Alchemy Semi Pb1000 boards specific pcmcia routines. - * - * Copyright 2002 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * ######################################################################## - * - * This program is free software; you can distribute 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 it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/proc_fs.h> -#include <linux/types.h> - -#include <pcmcia/ss.h> -#include <pcmcia/cistpl.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> - -#include <asm/au1000.h> -#include <asm/au1000_pcmcia.h> - -#define debug(fmt, arg...) do { } while (0) - -#include <asm/pb1000.h> -#define PCMCIA_IRQ AU1000_GPIO_15 - -static int pb1x00_pcmcia_init(struct pcmcia_init *init) -{ - u16 pcr; - pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; - - au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */ - au_sync_delay(100); - au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */ - au_sync(); - - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); - au_writel(pcr, PB1000_PCR); - au_sync_delay(20); - - return PCMCIA_NUM_SOCKS; -} - -static int pb1x00_pcmcia_shutdown(void) -{ - u16 pcr; - pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST; - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0); - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1); - au_writel(pcr, PB1000_PCR); - au_sync_delay(20); - return 0; -} - -static int -pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state) -{ - u32 inserted0, inserted1; - u16 vs0, vs1; - - vs0 = vs1 = (u16)au_readl(PB1000_ACR1); - inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2)); - inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2)); - vs0 = (vs0 >> 4) & 0x3; - vs1 = (vs1 >> 12) & 0x3; - - state->ready = 0; - state->vs_Xv = 0; - state->vs_3v = 0; - state->detect = 0; - - if (sock == 0) { - if (inserted0) { - switch (vs0) { - case 0: - case 2: - state->vs_3v=1; - break; - case 3: /* 5V */ - break; - default: - /* return without setting 'detect' */ - printk(KERN_ERR "pb1x00 bad VS (%d)\n", - vs0); - return 0; - } - state->detect = 1; - } - } - else { - if (inserted1) { - switch (vs1) { - case 0: - case 2: - state->vs_3v=1; - break; - case 3: /* 5V */ - break; - default: - /* return without setting 'detect' */ - printk(KERN_ERR "pb1x00 bad VS (%d)\n", - vs1); - return 0; - } - state->detect = 1; - } - } - - if (state->detect) { - state->ready = 1; - } - - state->bvd1=1; - state->bvd2=1; - state->wrprot=0; - return 1; -} - - -static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info) -{ - - if(info->sock > PCMCIA_MAX_SOCK) return -1; - - /* - * Even in the case of the Pb1000, both sockets are connected - * to the same irq line. - */ - info->irq = PCMCIA_IRQ; - - return 0; -} - - -static int -pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure) -{ - u16 pcr; - - if(configure->sock > PCMCIA_MAX_SOCK) return -1; - - pcr = au_readl(PB1000_PCR); - - if (configure->sock == 0) { - pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 | - PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1); - } - else { - pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 | - PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1); - } - - pcr &= ~PCR_SLOT_0_RST; - debug("Vcc %dV Vpp %dV, pcr %x\n", - configure->vcc, configure->vpp, pcr); - switch(configure->vcc){ - case 0: /* Vcc 0 */ - switch(configure->vpp) { - case 0: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND, - configure->sock); - break; - case 12: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V, - configure->sock); - break; - case 50: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V, - configure->sock); - break; - case 33: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V, - configure->sock); - break; - default: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, - configure->sock); - printk("%s: bad Vcc/Vpp (%d:%d)\n", - __func__, - configure->vcc, - configure->vpp); - break; - } - break; - case 50: /* Vcc 5V */ - switch(configure->vpp) { - case 0: - pcr |= SET_VCC_VPP(VCC_5V,VPP_GND, - configure->sock); - break; - case 50: - pcr |= SET_VCC_VPP(VCC_5V,VPP_5V, - configure->sock); - break; - case 12: - pcr |= SET_VCC_VPP(VCC_5V,VPP_12V, - configure->sock); - break; - case 33: - pcr |= SET_VCC_VPP(VCC_5V,VPP_3V, - configure->sock); - break; - default: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, - configure->sock); - printk("%s: bad Vcc/Vpp (%d:%d)\n", - __func__, - configure->vcc, - configure->vpp); - break; - } - break; - case 33: /* Vcc 3.3V */ - switch(configure->vpp) { - case 0: - pcr |= SET_VCC_VPP(VCC_3V,VPP_GND, - configure->sock); - break; - case 50: - pcr |= SET_VCC_VPP(VCC_3V,VPP_5V, - configure->sock); - break; - case 12: - pcr |= SET_VCC_VPP(VCC_3V,VPP_12V, - configure->sock); - break; - case 33: - pcr |= SET_VCC_VPP(VCC_3V,VPP_3V, - configure->sock); - break; - default: - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ, - configure->sock); - printk("%s: bad Vcc/Vpp (%d:%d)\n", - __func__, - configure->vcc, - configure->vpp); - break; - } - break; - default: /* what's this ? */ - pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock); - printk(KERN_ERR "%s: bad Vcc %d\n", - __func__, configure->vcc); - break; - } - - if (configure->sock == 0) { - pcr &= ~(PCR_SLOT_0_RST); - if (configure->reset) - pcr |= PCR_SLOT_0_RST; - } - else { - pcr &= ~(PCR_SLOT_1_RST); - if (configure->reset) - pcr |= PCR_SLOT_1_RST; - } - au_writel(pcr, PB1000_PCR); - au_sync_delay(300); - - return 0; -} - - -struct pcmcia_low_level pb1x00_pcmcia_ops = { - pb1x00_pcmcia_init, - pb1x00_pcmcia_shutdown, - pb1x00_pcmcia_socket_state, - pb1x00_pcmcia_get_irq_info, - pb1x00_pcmcia_configure_socket -}; diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 3e49df6d5e3b..5b7c22784aff 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -7,7 +7,7 @@ /* This is a fairly generic PCMCIA socket driver suitable for the * following Alchemy Development boards: - * Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200. + * Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200, Db1300 * * The Db1000 is used as a reference: Per-socket card-, carddetect- and * statuschange IRQs connected to SoC GPIOs, control and status register @@ -18,6 +18,7 @@ * - Pb1100/Pb1500: single socket only; voltage key bits VS are * at STATUS[5:4] (instead of STATUS[1:0]). * - Au1200-based: additional card-eject irqs, irqs not gpios! + * - Db1300: Db1200-like, no pwr ctrl, single socket (#1). */ #include <linux/delay.h> @@ -59,11 +60,17 @@ struct db1x_pcmcia_sock { #define BOARD_TYPE_DEFAULT 0 /* most boards */ #define BOARD_TYPE_DB1200 1 /* IRQs aren't gpios */ #define BOARD_TYPE_PB1100 2 /* VS bits slightly different */ +#define BOARD_TYPE_DB1300 3 /* no power control */ int board_type; }; #define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket) +static int db1300_card_inserted(struct db1x_pcmcia_sock *sock) +{ + return bcsr_read(BCSR_SIGSTAT) & (1 << 8); +} + /* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */ static int db1200_card_inserted(struct db1x_pcmcia_sock *sock) { @@ -84,6 +91,8 @@ static int db1x_card_inserted(struct db1x_pcmcia_sock *sock) switch (sock->board_type) { case BOARD_TYPE_DB1200: return db1200_card_inserted(sock); + case BOARD_TYPE_DB1300: + return db1300_card_inserted(sock); default: return db1000_card_inserted(sock); } @@ -160,7 +169,8 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) * ejection handler have been registered and the currently * active one disabled. */ - if (sock->board_type == BOARD_TYPE_DB1200) { + if ((sock->board_type == BOARD_TYPE_DB1200) || + (sock->board_type == BOARD_TYPE_DB1300)) { ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq, IRQF_DISABLED, "pcmcia_insert", sock); if (ret) @@ -174,7 +184,7 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) } /* enable the currently silent one */ - if (db1200_card_inserted(sock)) + if (db1x_card_inserted(sock)) enable_irq(sock->eject_irq); else enable_irq(sock->insert_irq); @@ -270,7 +280,8 @@ static int db1x_pcmcia_configure(struct pcmcia_socket *skt, } /* create new voltage code */ - cr_set |= ((v << 2) | p) << (sock->nr * 8); + if (sock->board_type != BOARD_TYPE_DB1300) + cr_set |= ((v << 2) | p) << (sock->nr * 8); changed = state->flags ^ sock->old_flags; @@ -343,6 +354,10 @@ static int db1x_pcmcia_get_status(struct pcmcia_socket *skt, /* if Vcc is not zero, we have applied power to a card */ status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0; + /* DB1300: power always on, but don't tell when no card present */ + if ((sock->board_type == BOARD_TYPE_DB1300) && (status & SS_DETECT)) + status = SS_POWERON | SS_3VCARD | SS_DETECT; + /* reset de-asserted? then we're ready */ status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET; @@ -419,6 +434,9 @@ static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200: sock->board_type = BOARD_TYPE_DB1200; break; + case BCSR_WHOAMI_DB1300: + sock->board_type = BOARD_TYPE_DB1300; + break; default: printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid); ret = -ENODEV; diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 9dc565c615bd..849c0c11d2af 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -24,15 +24,15 @@ #include "yenta_socket.h" #include "i82365.h" -static int disable_clkrun; +static bool disable_clkrun; module_param(disable_clkrun, bool, 0444); MODULE_PARM_DESC(disable_clkrun, "If PC card doesn't function properly, please try this option"); -static int isa_probe = 1; +static bool isa_probe = 1; module_param(isa_probe, bool, 0444); MODULE_PARM_DESC(isa_probe, "If set ISA interrupts are probed (default). Set to N to disable probing"); -static int pwr_irqs_off; +static bool pwr_irqs_off; module_param(pwr_irqs_off, bool, 0644); MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!"); diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 8877b836d27c..d96734478324 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -189,7 +189,7 @@ struct compal_data{ /* =============== */ /* General globals */ /* =============== */ -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index 7f88c7923fc6..6ee0b5c90933 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -95,7 +95,7 @@ #define OT_EC_BL_CONTROL_ON_DATA 0x1A -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index f204643c5052..bb5132128b33 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -89,7 +89,7 @@ static int msi_laptop_resume(struct platform_device *device); #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 09e26bfd4643..fd73ea89b857 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -228,12 +228,12 @@ static struct platform_device *sdev; static struct rfkill *rfk; static bool has_stepping_quirk; -static int force; +static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Disable the DMI check and forces the driver to be loaded"); -static int debug; +static bool debug; module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 62533c105da4..ea0c6075b720 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -378,13 +378,13 @@ static unsigned int bright_maxlvl; /* 0 = unknown */ #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES static int dbg_wlswemul; -static int tpacpi_wlsw_emulstate; +static bool tpacpi_wlsw_emulstate; static int dbg_bluetoothemul; -static int tpacpi_bluetooth_emulstate; +static bool tpacpi_bluetooth_emulstate; static int dbg_wwanemul; -static int tpacpi_wwan_emulstate; +static bool tpacpi_wwan_emulstate; static int dbg_uwbemul; -static int tpacpi_uwb_emulstate; +static bool tpacpi_uwb_emulstate; #endif @@ -6444,7 +6444,7 @@ static struct ibm_struct brightness_driver_data = { static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */ static char *alsa_id = "ThinkPadEC"; -static int alsa_enable = SNDRV_DEFAULT_ENABLE1; +static bool alsa_enable = SNDRV_DEFAULT_ENABLE1; struct tpacpi_alsa_data { struct snd_card *card; @@ -6487,7 +6487,7 @@ static enum tpacpi_volume_access_mode volume_mode = TPACPI_VOL_MODE_MAX; static enum tpacpi_volume_capabilities volume_capabilities; -static int volume_control_allowed; +static bool volume_control_allowed; /* * Used to syncronize writers to TP_EC_AUDIO and @@ -7265,7 +7265,7 @@ enum fan_control_commands { * and also watchdog cmd */ }; -static int fan_control_allowed; +static bool fan_control_allowed; static enum fan_status_access_mode fan_status_access_mode; static enum fan_control_access_mode fan_control_access_mode; @@ -8437,7 +8437,7 @@ static struct proc_dir_entry *proc_dir; * Module and infrastructure proble, init and exit handling */ -static int force_load; +static bool force_load; #ifdef CONFIG_THINKPAD_ACPI_DEBUG static const char * __init str_supported(int is_supported) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index a134c26870b0..42a4dcc25f92 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -82,12 +82,12 @@ struct wmi_block { #define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */ #define ACPI_WMI_EVENT 0x8 /* GUID is an event */ -static int debug_event; +static bool debug_event; module_param(debug_event, bool, 0444); MODULE_PARM_DESC(debug_event, "Log WMI Events [0/1]"); -static int debug_dump_wdg; +static bool debug_dump_wdg; module_param(debug_dump_wdg, bool, 0444); MODULE_PARM_DESC(debug_dump_wdg, "Dump available WMI interfaces [0/1]"); diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index 545874b1df9e..076e211a40b7 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -64,7 +64,7 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); -static unsigned int pmod_enabled; +static bool pmod_enabled; module_param(pmod_enabled, bool, 0644); MODULE_PARM_DESC(pmod_enabled, "PMOD enable bit"); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index e91b8ddc2793..c9b92531ae60 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -16,8 +16,8 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/platform_device.h> -#include <linux/mfd/ab8500.h> #include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab8500.h> diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index a0a9810adf0b..4bcf9ca2818a 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -15,7 +15,7 @@ #include <linux/platform_device.h> #include <linux/rtc.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #include <linux/delay.h> #define AB8500_RTC_SOFF_STAT_REG 0x00 diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 4a5529346b47..2d71943bc436 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -261,6 +261,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) /* XXX - isn't this redundant? */ platform_set_drvdata(pdev, info); + device_init_wakeup(&pdev->dev, 1); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -290,10 +292,34 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int max8925_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + + if (device_may_wakeup(dev)) + chip->wakeup_flag |= 1 << MAX8925_IRQ_RTC_ALARM0; + return 0; +} +static int max8925_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); + + if (device_may_wakeup(dev)) + chip->wakeup_flag &= ~(1 << MAX8925_IRQ_RTC_ALARM0); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume); + static struct platform_driver max8925_rtc_driver = { .driver = { .name = "max8925-rtc", .owner = THIS_MODULE, + .pm = &max8925_rtc_pm_ops, }, .probe = max8925_rtc_probe, .remove = __devexit_p(max8925_rtc_remove), diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index e5cb9248a442..f3b8bb84faf2 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -75,7 +75,7 @@ static LIST_HEAD(raw3270_devices); static int raw3270_registered; /* Module parameters */ -static int tubxcorrect = 0; +static bool tubxcorrect = 0; module_param(tubxcorrect, bool, 0); /* diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 11312f401c70..2211277a1079 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c @@ -28,9 +28,9 @@ #define MAX_CMDLEN 240 #define MIN_INTERVAL 15 static char vmwdt_cmd[MAX_CMDLEN] = "IPL"; -static int vmwdt_conceal; +static bool vmwdt_conceal; -static int vmwdt_nowayout = WATCHDOG_NOWAYOUT; +static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT; MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 2985eb439485..204ca728e7fd 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -98,7 +98,7 @@ enum cmb_format { * enum cmb_format. */ static int format = CMF_AUTODETECT; -module_param(format, bool, 0444); +module_param(format, bint, 0444); /** * struct cmb_operations - functions to use depending on cmb_format diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 195823a51aab..ed119cedaae0 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -102,7 +102,7 @@ static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 }; */ #if defined(MODULE) -static int isapnp = 0; +static bool isapnp = 0; static int aha1542[] = {0x330, 11, 4, -1}; module_param_array(aha1542, int, NULL, 0); module_param(isapnp, bool, 0); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index f5b718d3c31b..13aeca3d51f2 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -546,7 +546,7 @@ static struct ParameterData __devinitdata cfg_data[] = { * command line overrides will be used. If set to 1 then safe and * slow settings will be used. */ -static int use_safe_settings = 0; +static bool use_safe_settings = 0; module_param_named(safe, use_safe_settings, bool, 0); MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false"); diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index f6a50c98c36f..002924963cd8 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -59,11 +59,11 @@ MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra2 #define ASYNC_MODE 1 #define ULTRA20M_MODE 2 -static int auto_param = 0; /* default: ON */ +static bool auto_param = 0; /* default: ON */ module_param (auto_param, bool, 0); MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)"); -static int disc_priv = 1; /* default: OFF */ +static bool disc_priv = 1; /* default: OFF */ module_param (disc_priv, bool, 0); MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))"); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index ca86721a71b9..b61a753eb896 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -70,7 +70,7 @@ module_param(nsp_burst_mode, int, 0); MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); /* Release IO ports after configuration? */ -static int free_ports = 0; +static bool free_ports = 0; module_param(free_ports, bool, 0); MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 44f76e8b58af..c77628afbf9f 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -112,7 +112,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb) goto next_msg; } - if (security_netlink_recv(skb, CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { err = -EPERM; goto next_msg; } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b3c6d957fbd8..89da43f73c00 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -297,7 +297,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, kfree(sdev); goto out; } - blk_get_queue(sdev->request_queue); + WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); sdev->request_queue->queuedata = sdev; scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7b3f8075e2a5..c691fb50e6cb 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1075,6 +1075,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " "cmd=0x%x\n", disk->disk_name, cmd)); + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -1097,7 +1101,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, error = scsi_ioctl(sdp, cmd, p); break; default: - error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); + error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); if (error != -ENOTTY) break; error = scsi_ioctl(sdp, cmd, p); @@ -1267,6 +1271,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + int ret; + + ret = scsi_verify_blk_ioctl(bdev, cmd); + if (ret < 0) + return ret; /* * If we are in the middle of error recovery, don't let anyone @@ -1278,8 +1287,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, return -ENODEV; if (sdev->host->hostt->compat_ioctl) { - int ret; - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); return ret; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 56abf55e49da..3f9a47ec67dc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -87,12 +87,12 @@ config SPI_BFIN_SPORT Enable support for a SPI bus via the Blackfin SPORT peripheral. config SPI_AU1550 - tristate "Au1550/Au12x0 SPI Controller" + tristate "Au1550/Au1200/Au1300 SPI Controller" depends on MIPS_ALCHEMY && EXPERIMENTAL select SPI_BITBANG help If you say yes to this option, support will be included for the - Au1550 SPI controller (may also work with Au1200,Au1210,Au1250). + PSC SPI controller found on Au1550, Au1200 and Au1300 series. config SPI_BITBANG tristate "Utilities for Bitbanging SPI masters" @@ -332,8 +332,7 @@ config SPI_STMP3XXX config SPI_TEGRA tristate "Nvidia Tegra SPI controller" - depends on ARCH_TEGRA - select TEGRA_SYSTEM_DMA + depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA help SPI driver for NVidia Tegra SoCs diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 0d18d80bcd25..9bcf87ae4c00 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -61,7 +61,7 @@ EXPORT_SYMBOL(comedi_debug); module_param(comedi_debug, int, 0644); #endif -int comedi_autoconfig = 1; +bool comedi_autoconfig = 1; module_param(comedi_autoconfig, bool, 0444); static int comedi_num_legacy_minors; diff --git a/drivers/staging/comedi/comedi_fops.h b/drivers/staging/comedi/comedi_fops.h index da4b4f5553f5..006cf14c577a 100644 --- a/drivers/staging/comedi/comedi_fops.h +++ b/drivers/staging/comedi/comedi_fops.h @@ -1,10 +1,11 @@ #ifndef _COMEDI_FOPS_H #define _COMEDI_FOPS_H +#include <linux/types.h> extern struct class *comedi_class; extern const struct file_operations comedi_fops; -extern int comedi_autoconfig; +extern bool comedi_autoconfig; extern struct comedi_driver *comedi_drivers; #endif /* _COMEDI_FOPS_H */ diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig index 5865029db0f6..28aba00dc629 100644 --- a/drivers/staging/media/as102/Kconfig +++ b/drivers/staging/media/as102/Kconfig @@ -1,6 +1,7 @@ config DVB_AS102 tristate "Abilis AS102 DVB receiver" depends on DVB_CORE && USB && I2C && INPUT + select FW_LOADER help Choose Y or M here if you have a device containing an AS102 diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile index e7dbb6f814d5..1bca43e847c7 100644 --- a/drivers/staging/media/as102/Makefile +++ b/drivers/staging/media/as102/Makefile @@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ obj-$(CONFIG_DVB_AS102) += dvb-as102.o -EXTRA_CFLAGS += -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index 828526d4c289..aae0505a36c4 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -24,7 +24,7 @@ #include <linux/module.h> #include <linux/mm.h> #include <linux/kref.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/usb.h> /* header file for Usb device driver*/ @@ -56,13 +56,11 @@ int elna_enable = 1; module_param_named(elna_enable, elna_enable, int, 0644); MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); -#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#endif static void as102_stop_stream(struct as102_dev_t *dev) { - struct as102_bus_adapter_t *bus_adap; + struct as10x_bus_adapter_t *bus_adap; if (dev != NULL) bus_adap = &dev->bus_adap; @@ -85,7 +83,7 @@ static void as102_stop_stream(struct as102_dev_t *dev) static int as102_start_stream(struct as102_dev_t *dev) { - struct as102_bus_adapter_t *bus_adap; + struct as10x_bus_adapter_t *bus_adap; int ret = -EFAULT; if (dev != NULL) @@ -111,7 +109,7 @@ static int as102_start_stream(struct as102_dev_t *dev) static int as10x_pid_filter(struct as102_dev_t *dev, int index, u16 pid, int onoff) { - struct as102_bus_adapter_t *bus_adap = &dev->bus_adap; + struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap; int ret = -EFAULT; ENTER(); @@ -123,22 +121,22 @@ static int as10x_pid_filter(struct as102_dev_t *dev, switch (onoff) { case 0: - ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); - dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", - index, pid, ret); - break; + ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); + dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", + index, pid, ret); + break; case 1: { - struct as10x_ts_filter filter; + struct as10x_ts_filter filter; - filter.type = TS_PID_TYPE_TS; - filter.idx = 0xFF; - filter.pid = pid; + filter.type = TS_PID_TYPE_TS; + filter.idx = 0xFF; + filter.pid = pid; - ret = as10x_cmd_add_PID_filter(bus_adap, &filter); - dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", - index, filter.idx, filter.pid, ret); - break; + ret = as10x_cmd_add_PID_filter(bus_adap, &filter); + dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", + index, filter.idx, filter.pid, ret); + break; } } @@ -159,10 +157,9 @@ static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (mutex_lock_interruptible(&as102_dev->sem)) return -ERESTARTSYS; - if (pid_filtering) { - as10x_pid_filter(as102_dev, - dvbdmxfeed->index, dvbdmxfeed->pid, 1); - } + if (pid_filtering) + as10x_pid_filter(as102_dev, dvbdmxfeed->index, + dvbdmxfeed->pid, 1); if (as102_dev->streaming++ == 0) ret = as102_start_stream(as102_dev); @@ -185,10 +182,9 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) if (--as102_dev->streaming == 0) as102_stop_stream(as102_dev); - if (pid_filtering) { - as10x_pid_filter(as102_dev, - dvbdmxfeed->index, dvbdmxfeed->pid, 0); - } + if (pid_filtering) + as10x_pid_filter(as102_dev, dvbdmxfeed->index, + dvbdmxfeed->pid, 0); mutex_unlock(&as102_dev->sem); LEAVE(); @@ -197,27 +193,16 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) int as102_dvb_register(struct as102_dev_t *as102_dev) { - int ret = 0; - ENTER(); + struct device *dev = &as102_dev->bus_adap.usb_dev->dev; + int ret; ret = dvb_register_adapter(&as102_dev->dvb_adap, - as102_dev->name, - THIS_MODULE, -#if defined(CONFIG_AS102_USB) - &as102_dev->bus_adap.usb_dev->dev -#elif defined(CONFIG_AS102_SPI) - &as102_dev->bus_adap.spi_dev->dev -#else -#error >>> dvb_register_adapter <<< -#endif -#ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR - , adapter_nr -#endif - ); + as102_dev->name, THIS_MODULE, + dev, adapter_nr); if (ret < 0) { - err("%s: dvb_register_adapter() failed (errno = %d)", - __func__, ret); - goto failed; + dev_err(dev, "%s: dvb_register_adapter() failed: %d\n", + __func__, ret); + return ret; } as102_dev->dvb_dmx.priv = as102_dev; @@ -235,22 +220,22 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) ret = dvb_dmx_init(&as102_dev->dvb_dmx); if (ret < 0) { - err("%s: dvb_dmx_init() failed (errno = %d)", __func__, ret); - goto failed; + dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret); + goto edmxinit; } ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); if (ret < 0) { - err("%s: dvb_dmxdev_init() failed (errno = %d)", __func__, - ret); - goto failed; + dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n", + __func__, ret); + goto edmxdinit; } ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); if (ret < 0) { - err("%s: as102_dvb_register_frontend() failed (errno = %d)", + dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d", __func__, ret); - goto failed; + goto efereg; } /* init bus mutex for token locking */ @@ -259,7 +244,6 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) /* init start / stop stream mutex */ mutex_init(&as102_dev->sem); -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) /* * try to load as102 firmware. If firmware upload failed, we'll be * able to upload it later. @@ -267,18 +251,21 @@ int as102_dvb_register(struct as102_dev_t *as102_dev) if (fw_upload) try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), "firmware_class"); -#endif -failed: - LEAVE(); - /* FIXME: free dvb_XXX */ + pr_info("Registered device %s", as102_dev->name); + return 0; + +efereg: + dvb_dmxdev_release(&as102_dev->dvb_dmxdev); +edmxdinit: + dvb_dmx_release(&as102_dev->dvb_dmx); +edmxinit: + dvb_unregister_adapter(&as102_dev->dvb_adap); return ret; } void as102_dvb_unregister(struct as102_dev_t *as102_dev) { - ENTER(); - /* unregister as102 frontend */ as102_dvb_unregister_fe(&as102_dev->dvb_fe); @@ -289,28 +276,18 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev) /* unregister dvb adapter */ dvb_unregister_adapter(&as102_dev->dvb_adap); - LEAVE(); + pr_info("Unregistered device %s", as102_dev->name); } static int __init as102_driver_init(void) { - int ret = 0; - - ENTER(); + int ret; /* register this driver with the low level subsystem */ -#if defined(CONFIG_AS102_USB) ret = usb_register(&as102_usb_driver); if (ret) err("usb_register failed (ret = %d)", ret); -#endif -#if defined(CONFIG_AS102_SPI) - ret = spi_register_driver(&as102_spi_driver); - if (ret) - printk(KERN_ERR "spi_register failed (ret = %d)", ret); -#endif - LEAVE(); return ret; } @@ -327,15 +304,8 @@ module_init(as102_driver_init); */ static void __exit as102_driver_exit(void) { - ENTER(); /* deregister this driver with the low level bus subsystem */ -#if defined(CONFIG_AS102_USB) usb_deregister(&as102_usb_driver); -#endif -#if defined(CONFIG_AS102_SPI) - spi_unregister_driver(&as102_spi_driver); -#endif - LEAVE(); } /* @@ -347,5 +317,3 @@ module_exit(as102_driver_exit); MODULE_DESCRIPTION(DRIVER_FULL_NAME); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>"); - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index fd33f5a12dcc..957f0ed0d81a 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -17,38 +17,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(CONFIG_AS102_USB) #include <linux/usb.h> -extern struct usb_driver as102_usb_driver; -#endif - -#if defined(CONFIG_AS102_SPI) -#include <linux/platform_device.h> -#include <linux/spi/spi.h> -#include <linux/cdev.h> - -extern struct spi_driver as102_spi_driver; -#endif - -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dmxdev.h" +#include <dvb_demux.h> +#include <dvb_frontend.h> +#include <dmxdev.h> +#include "as10x_cmd.h" +#include "as102_usb_drv.h" #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" #define DRIVER_NAME "as10x_usb" extern int as102_debug; #define debug as102_debug +extern struct usb_driver as102_usb_driver; +extern int elna_enable; #define dprintk(debug, args...) \ do { if (debug) { \ - printk(KERN_DEBUG "%s: ",__FUNCTION__); \ + pr_debug("%s: ", __func__); \ printk(args); \ } } while (0) #ifdef TRACE -#define ENTER() printk(">> enter %s\n", __FUNCTION__) -#define LEAVE() printk("<< leave %s\n", __FUNCTION__) +#define ENTER() pr_debug(">> enter %s\n", __func__) +#define LEAVE() pr_debug("<< leave %s\n", __func__) #else #define ENTER() #define LEAVE() @@ -59,39 +51,14 @@ extern int as102_debug; #define AS102_USB_BUF_SIZE 512 #define MAX_STREAM_URB 32 -#include "as10x_cmd.h" - -#if defined(CONFIG_AS102_USB) -#include "as102_usb_drv.h" -#endif - -#if defined(CONFIG_AS102_SPI) -#include "as10x_spi_drv.h" -#endif - - -struct as102_bus_adapter_t { -#if defined(CONFIG_AS102_USB) +struct as10x_bus_adapter_t { struct usb_device *usb_dev; -#elif defined(CONFIG_AS102_SPI) - struct spi_device *spi_dev; - struct cdev cdev; /* spidev raw device */ - - struct timer_list timer; - struct completion xfer_done; -#endif /* bus token lock */ struct mutex lock; /* low level interface for bus adapter */ union as10x_bus_token_t { -#if defined(CONFIG_AS102_USB) /* usb token */ struct as10x_usb_token_cmd_t usb; -#endif -#if defined(CONFIG_AS102_SPI) - /* spi token */ - struct as10x_spi_token_cmd_t spi; -#endif } token; /* token cmd xfer id */ @@ -106,7 +73,7 @@ struct as102_bus_adapter_t { struct as102_dev_t { const char *name; - struct as102_bus_adapter_t bus_adap; + struct as10x_bus_adapter_t bus_adap; struct list_head device_entry; struct kref kref; unsigned long minor; @@ -138,5 +105,3 @@ void as102_dvb_unregister(struct as102_dev_t *dev); int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); int as102_dvb_unregister_fe(struct dvb_frontend *dev); - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c index 3550f905367e..bdc5a38cddf7 100644 --- a/drivers/staging/media/as102/as102_fe.c +++ b/drivers/staging/media/as102/as102_fe.c @@ -23,17 +23,15 @@ #include "as10x_types.h" #include "as10x_cmd.h" -extern int elna_enable; - -static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, +static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst, struct as10x_tps *src); static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, - struct dvb_frontend_parameters *src); + struct dtv_frontend_properties *src); -static int as102_fe_set_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) +static int as102_fe_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret = 0; struct as102_dev_t *dev; struct as10x_tune_args tune_args = { 0 }; @@ -47,7 +45,7 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe, if (mutex_lock_interruptible(&dev->bus_adap.lock)) return -EBUSY; - as102_fe_copy_tune_parameters(&tune_args, params); + as102_fe_copy_tune_parameters(&tune_args, p); /* send abilis command: SET_TUNE */ ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); @@ -60,8 +58,9 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe, return (ret < 0) ? -EINVAL : 0; } -static int as102_fe_get_frontend(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) { +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; int ret = 0; struct as102_dev_t *dev; struct as10x_tps tps = { 0 }; @@ -280,9 +279,9 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) } static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "Unknown AS102 device", - .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, @@ -346,38 +345,36 @@ int as102_dvb_register_fe(struct as102_dev_t *as102_dev, return errno; } -static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, +static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps, struct as10x_tps *as10x_tps) { - struct dvb_ofdm_parameters *fe_tps = &dst->u.ofdm; - /* extract consteallation */ - switch (as10x_tps->constellation) { + switch (as10x_tps->modulation) { case CONST_QPSK: - fe_tps->constellation = QPSK; + fe_tps->modulation = QPSK; break; case CONST_QAM16: - fe_tps->constellation = QAM_16; + fe_tps->modulation = QAM_16; break; case CONST_QAM64: - fe_tps->constellation = QAM_64; + fe_tps->modulation = QAM_64; break; } /* extract hierarchy */ switch (as10x_tps->hierarchy) { case HIER_NONE: - fe_tps->hierarchy_information = HIERARCHY_NONE; + fe_tps->hierarchy = HIERARCHY_NONE; break; case HIER_ALPHA_1: - fe_tps->hierarchy_information = HIERARCHY_1; + fe_tps->hierarchy = HIERARCHY_1; break; case HIER_ALPHA_2: - fe_tps->hierarchy_information = HIERARCHY_2; + fe_tps->hierarchy = HIERARCHY_2; break; case HIER_ALPHA_4: - fe_tps->hierarchy_information = HIERARCHY_4; + fe_tps->hierarchy = HIERARCHY_4; break; } @@ -475,7 +472,7 @@ static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) } static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, - struct dvb_frontend_parameters *params) + struct dtv_frontend_properties *params) { /* set frequency */ @@ -484,21 +481,21 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, /* fix interleaving_mode */ tune_args->interleaving_mode = INTLV_NATIVE; - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_8_MHZ: + switch (params->bandwidth_hz) { + case 8000000: tune_args->bandwidth = BW_8_MHZ; break; - case BANDWIDTH_7_MHZ: + case 7000000: tune_args->bandwidth = BW_7_MHZ; break; - case BANDWIDTH_6_MHZ: + case 6000000: tune_args->bandwidth = BW_6_MHZ; break; default: tune_args->bandwidth = BW_8_MHZ; } - switch (params->u.ofdm.guard_interval) { + switch (params->guard_interval) { case GUARD_INTERVAL_1_32: tune_args->guard_interval = GUARD_INT_1_32; break; @@ -517,22 +514,22 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, break; } - switch (params->u.ofdm.constellation) { + switch (params->modulation) { case QPSK: - tune_args->constellation = CONST_QPSK; + tune_args->modulation = CONST_QPSK; break; case QAM_16: - tune_args->constellation = CONST_QAM16; + tune_args->modulation = CONST_QAM16; break; case QAM_64: - tune_args->constellation = CONST_QAM64; + tune_args->modulation = CONST_QAM64; break; default: - tune_args->constellation = CONST_UNKNOWN; + tune_args->modulation = CONST_UNKNOWN; break; } - switch (params->u.ofdm.transmission_mode) { + switch (params->transmission_mode) { case TRANSMISSION_MODE_2K: tune_args->transmission_mode = TRANS_MODE_2K; break; @@ -543,7 +540,7 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, tune_args->transmission_mode = TRANS_MODE_UNKNOWN; } - switch (params->u.ofdm.hierarchy_information) { + switch (params->hierarchy) { case HIERARCHY_NONE: tune_args->hierarchy = HIER_NONE; break; @@ -571,19 +568,19 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, * if HP/LP are both set to FEC_NONE, HP will be selected. */ if ((tune_args->hierarchy != HIER_NONE) && - ((params->u.ofdm.code_rate_LP == FEC_NONE) || - (params->u.ofdm.code_rate_HP == FEC_NONE))) { + ((params->code_rate_LP == FEC_NONE) || + (params->code_rate_HP == FEC_NONE))) { - if (params->u.ofdm.code_rate_LP == FEC_NONE) { + if (params->code_rate_LP == FEC_NONE) { tune_args->hier_select = HIER_HIGH_PRIORITY; tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + as102_fe_get_code_rate(params->code_rate_HP); } - if (params->u.ofdm.code_rate_HP == FEC_NONE) { + if (params->code_rate_HP == FEC_NONE) { tune_args->hier_select = HIER_LOW_PRIORITY; tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_LP); + as102_fe_get_code_rate(params->code_rate_LP); } dprintk(debug, "\thierarchy: 0x%02x " @@ -596,8 +593,6 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, tune_args->code_rate); } else { tune_args->code_rate = - as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); + as102_fe_get_code_rate(params->code_rate_HP); } } - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c index c019df933cc9..43ebc43e6b9a 100644 --- a/drivers/staging/media/as102/as102_fw.c +++ b/drivers/staging/media/as102/as102_fw.c @@ -26,7 +26,6 @@ #include "as102_drv.h" #include "as102_fw.h" -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) char as102_st_fw1[] = "as102_data1_st.hex"; char as102_st_fw2[] = "as102_data2_st.hex"; char as102_dt_fw1[] = "as102_data1_dt.hex"; @@ -59,7 +58,7 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, unsigned char *src, dst; if (*fw_data++ != ':') { - printk(KERN_ERR "invalid firmware file\n"); + pr_err("invalid firmware file\n"); return -EFAULT; } @@ -102,7 +101,7 @@ static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, return (count * 2) + 2; } -static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, +static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, unsigned char *cmd, const struct firmware *firmware) { @@ -163,19 +162,14 @@ error: return (errno == 0) ? total_read_bytes : errno; } -int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) +int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) { int errno = -EFAULT; const struct firmware *firmware; unsigned char *cmd_buf = NULL; char *fw1, *fw2; - -#if defined(CONFIG_AS102_USB) struct usb_device *dev = bus_adap->usb_dev; -#endif -#if defined(CONFIG_AS102_SPI) - struct spi_device *dev = bus_adap->spi_dev; -#endif + ENTER(); /* select fw file to upload */ @@ -187,7 +181,6 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) fw2 = as102_st_fw2; } -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) /* allocate buffer to store firmware upload command and data */ cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); if (cmd_buf == NULL) { @@ -198,21 +191,21 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) /* request kernel to locate firmware file: part1 */ errno = request_firmware(&firmware, fw1, &dev->dev); if (errno < 0) { - printk(KERN_ERR "%s: unable to locate firmware file: %s\n", - DRIVER_NAME, fw1); + pr_err("%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw1); goto error; } /* initiate firmware upload */ errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); if (errno < 0) { - printk(KERN_ERR "%s: error during firmware upload part1\n", - DRIVER_NAME); + pr_err("%s: error during firmware upload part1\n", + DRIVER_NAME); goto error; } - printk(KERN_INFO "%s: fimrware: %s loaded with success\n", - DRIVER_NAME, fw1); + pr_info("%s: firmware: %s loaded with success\n", + DRIVER_NAME, fw1); release_firmware(firmware); /* wait for boot to complete */ @@ -221,31 +214,28 @@ int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) /* request kernel to locate firmware file: part2 */ errno = request_firmware(&firmware, fw2, &dev->dev); if (errno < 0) { - printk(KERN_ERR "%s: unable to locate firmware file: %s\n", - DRIVER_NAME, fw2); + pr_err("%s: unable to locate firmware file: %s\n", + DRIVER_NAME, fw2); goto error; } /* initiate firmware upload */ errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); if (errno < 0) { - printk(KERN_ERR "%s: error during firmware upload part2\n", - DRIVER_NAME); + pr_err("%s: error during firmware upload part2\n", + DRIVER_NAME); goto error; } - printk(KERN_INFO "%s: fimrware: %s loaded with success\n", - DRIVER_NAME, fw2); + pr_info("%s: firmware: %s loaded with success\n", + DRIVER_NAME, fw2); error: /* free data buffer */ kfree(cmd_buf); /* release firmware if needed */ if (firmware != NULL) release_firmware(firmware); -#endif + LEAVE(); return errno; } -#endif - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h index 27e5347e2e19..bd21f0554392 100644 --- a/drivers/staging/media/as102/as102_fw.h +++ b/drivers/staging/media/as102/as102_fw.h @@ -20,11 +20,10 @@ extern int dual_tuner; -#pragma pack(1) struct as10x_raw_fw_pkt { unsigned char address[4]; unsigned char data[MAX_FW_PKT_SIZE - 6]; -}; +} __packed; struct as10x_fw_pkt_t { union { @@ -32,11 +31,8 @@ struct as10x_fw_pkt_t { unsigned char length[2]; } u; struct as10x_raw_fw_pkt raw; -}; -#pragma pack() +} __packed; #ifdef __KERNEL__ -int as102_fw_upload(struct as102_bus_adapter_t *bus_adap); +int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap); #endif - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c index 264be2dbd2a4..d775be0173ea 100644 --- a/drivers/staging/media/as102/as102_usb_drv.c +++ b/drivers/staging/media/as102/as102_usb_drv.c @@ -42,30 +42,32 @@ static struct usb_device_id as102_usb_id_table[] = { { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, + { USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) }, { } /* Terminating entry */ }; /* Note that this table must always have the same number of entries as the as102_usb_id_table struct */ -static const char *as102_device_names[] = { +static const char * const as102_device_names[] = { AS102_REFERENCE_DESIGN, AS102_PCTV_74E, AS102_ELGATO_EYETV_DTT_NAME, AS102_NBOX_DVBT_DONGLE_NAME, + AS102_SKY_IT_DIGITAL_KEY_NAME, NULL /* Terminating entry */ }; struct usb_driver as102_usb_driver = { - .name = DRIVER_FULL_NAME, - .probe = as102_usb_probe, - .disconnect = as102_usb_disconnect, - .id_table = as102_usb_id_table + .name = DRIVER_FULL_NAME, + .probe = as102_usb_probe, + .disconnect = as102_usb_disconnect, + .id_table = as102_usb_id_table }; static const struct file_operations as102_dev_fops = { - .owner = THIS_MODULE, - .open = as102_open, - .release = as102_release, + .owner = THIS_MODULE, + .open = as102_open, + .release = as102_release, }; static struct usb_class_driver as102_usb_class_driver = { @@ -74,7 +76,7 @@ static struct usb_class_driver as102_usb_class_driver = { .minor_base = AS102_DEVICE_MAJOR, }; -static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, +static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, unsigned char *recv_buf, int recv_buf_len) { @@ -131,7 +133,7 @@ static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, return ret; } -static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, +static int as102_send_ep1(struct as10x_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, int swap32) @@ -154,7 +156,7 @@ static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, return ret ? ret : actual_len; } -static int as102_read_ep2(struct as102_bus_adapter_t *bus_adap, +static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap, unsigned char *recv_buf, int recv_buf_len) { int ret = 0, actual_len; @@ -337,7 +339,7 @@ static void as102_usb_disconnect(struct usb_interface *intf) /* decrement usage counter */ kref_put(&as102_dev->kref, as102_usb_release); - printk(KERN_INFO "%s: device has been disconnected\n", DRIVER_NAME); + pr_info("%s: device has been disconnected\n", DRIVER_NAME); LEAVE(); } @@ -351,19 +353,19 @@ static int as102_usb_probe(struct usb_interface *intf, ENTER(); - as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); - if (as102_dev == NULL) { - err("%s: kzalloc failed", __func__); - return -ENOMEM; - } - /* This should never actually happen */ if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) != (sizeof(as102_device_names) / sizeof(const char *))) { - printk(KERN_ERR "Device names table invalid size"); + pr_err("Device names table invalid size"); return -EINVAL; } + as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); + if (as102_dev == NULL) { + err("%s: kzalloc failed", __func__); + return -ENOMEM; + } + /* Assign the user-friendly device name */ for (i = 0; i < (sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)); i++) { @@ -399,7 +401,7 @@ static int as102_usb_probe(struct usb_interface *intf, goto failed; } - printk(KERN_INFO "%s: device has been detected\n", DRIVER_NAME); + pr_info("%s: device has been detected\n", DRIVER_NAME); /* request buffer allocation for streaming */ ret = as102_alloc_usb_stream_buffer(as102_dev); @@ -432,8 +434,8 @@ static int as102_open(struct inode *inode, struct file *file) /* fetch device from usb interface */ intf = usb_find_interface(&as102_usb_driver, minor); if (intf == NULL) { - printk(KERN_ERR "%s: can't find device for minor %d\n", - __func__, minor); + pr_err("%s: can't find device for minor %d\n", + __func__, minor); ret = -ENODEV; goto exit; } @@ -474,5 +476,3 @@ static int as102_release(struct inode *inode, struct file *file) } MODULE_DEVICE_TABLE(usb, as102_usb_id_table); - -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h index fb1fc41dcd79..fc2884ab02a2 100644 --- a/drivers/staging/media/as102/as102_usb_drv.h +++ b/drivers/staging/media/as102/as102_usb_drv.h @@ -47,6 +47,11 @@ #define NBOX_DVBT_DONGLE_USB_VID 0x0b89 #define NBOX_DVBT_DONGLE_USB_PID 0x0007 +/* Sky Italia: Digital Key (green led) */ +#define AS102_SKY_IT_DIGITAL_KEY_NAME "Sky IT Digital Key (green led)" +#define SKY_IT_DIGITAL_KEY_USB_VID 0x2137 +#define SKY_IT_DIGITAL_KEY_USB_PID 0x0001 + void as102_urb_stream_irq(struct urb *urb); struct as10x_usb_token_cmd_t { @@ -56,4 +61,3 @@ struct as10x_usb_token_cmd_t { struct as10x_cmd_t r; }; #endif -/* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c index 0dcba8065780..262bb94ad27e 100644 --- a/drivers/staging/media/as102/as10x_cmd.c +++ b/drivers/staging/media/as102/as10x_cmd.c @@ -25,35 +25,35 @@ /** * as10x_cmd_turn_on - send turn on command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 when no error, < 0 in case of error. */ -int as10x_cmd_turn_on(as10x_handle_t *phandle) +int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.turn_on.req)); /* fill command */ pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, - sizeof(pcmd->body.turn_on.req) + - HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.turn_on.rsp) + - HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, + sizeof(pcmd->body.turn_on.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.turn_on.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -71,31 +71,31 @@ out: /** * as10x_cmd_turn_off - send turn off command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_turn_off(as10x_handle_t *phandle) +int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.turn_off.req)); /* fill command */ pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( - phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd( + adap, (uint8_t *) pcmd, sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); @@ -116,23 +116,24 @@ out: /** * as10x_cmd_set_tune - send set tune command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @ptune: tune parameters * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) +int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, + struct as10x_tune_args *ptune) { int error; struct as10x_cmd_t *preq, *prsp; ENTER(); - preq = phandle->cmd; - prsp = phandle->rsp; + preq = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(preq, (++phandle->cmd_xid), + as10x_cmd_build(preq, (++adap->cmd_xid), sizeof(preq->body.set_tune.req)); /* fill command */ @@ -140,7 +141,7 @@ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; preq->body.set_tune.req.args.hier_select = ptune->hier_select; - preq->body.set_tune.req.args.constellation = ptune->constellation; + preq->body.set_tune.req.args.modulation = ptune->modulation; preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; preq->body.set_tune.req.args.interleaving_mode = ptune->interleaving_mode; @@ -150,14 +151,14 @@ int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) ptune->transmission_mode; /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) preq, - sizeof(preq->body.set_tune.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.set_tune.rsp) - + HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) preq, + sizeof(preq->body.set_tune.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.set_tune.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -175,12 +176,12 @@ out: /** * as10x_cmd_get_tune_status - send get tune status command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @pstatus: pointer to updated status structure of the current tune * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_tune_status(as10x_handle_t *phandle, +int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, struct as10x_tune_status *pstatus) { int error; @@ -188,11 +189,11 @@ int as10x_cmd_get_tune_status(as10x_handle_t *phandle, ENTER(); - preq = phandle->cmd; - prsp = phandle->rsp; + preq = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(preq, (++phandle->cmd_xid), + as10x_cmd_build(preq, (++adap->cmd_xid), sizeof(preq->body.get_tune_status.req)); /* fill command */ @@ -200,9 +201,9 @@ int as10x_cmd_get_tune_status(as10x_handle_t *phandle, cpu_to_le16(CONTROL_PROC_GETTUNESTAT); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd( - phandle, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd( + adap, (uint8_t *) preq, sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, (uint8_t *) prsp, @@ -232,24 +233,24 @@ out: } /** - * send get TPS command to AS10x - * @phandle: pointer to AS10x handle + * as10x_cmd_get_tps - send get TPS command to AS10x + * @adap: pointer to AS10x handle * @ptps: pointer to TPS parameters structure * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) +int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.get_tps.req)); /* fill command */ @@ -257,14 +258,14 @@ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) cpu_to_le16(CONTROL_PROC_GETTPS); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.get_tps.req) + - HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.get_tps.rsp) + - HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.get_tps.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.get_tps.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -278,7 +279,7 @@ int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) goto out; /* Response OK -> get response data */ - ptps->constellation = prsp->body.get_tps.rsp.tps.constellation; + ptps->modulation = prsp->body.get_tps.rsp.tps.modulation; ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; @@ -296,12 +297,12 @@ out: /** * as10x_cmd_get_demod_stats - send get demod stats command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @pdemod_stats: pointer to demod stats parameters structure * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, +int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, struct as10x_demod_stats *pdemod_stats) { int error; @@ -309,11 +310,11 @@ int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.get_demod_stats.req)); /* fill command */ @@ -321,8 +322,8 @@ int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.get_demod_stats.req) + HEADER_SIZE, @@ -360,13 +361,13 @@ out: /** * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @is_ready: pointer to value indicating when impulse * response data is ready * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, +int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, uint8_t *is_ready) { int error; @@ -374,11 +375,11 @@ int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.get_impulse_rsp.req)); /* fill command */ @@ -386,8 +387,8 @@ int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.get_impulse_rsp.req) + HEADER_SIZE, diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h index 01a716380e0a..4ea249e7adab 100644 --- a/drivers/staging/media/as102/as10x_cmd.h +++ b/drivers/staging/media/as102/as10x_cmd.h @@ -28,459 +28,456 @@ /*********************************/ /* MACRO DEFINITIONS */ /*********************************/ -#define AS10X_CMD_ERROR -1 +#define AS10X_CMD_ERROR -1 -#define SERVICE_PROG_ID 0x0002 -#define SERVICE_PROG_VERSION 0x0001 +#define SERVICE_PROG_ID 0x0002 +#define SERVICE_PROG_VERSION 0x0001 -#define HIER_NONE 0x00 -#define HIER_LOW_PRIORITY 0x01 +#define HIER_NONE 0x00 +#define HIER_LOW_PRIORITY 0x01 #define HEADER_SIZE (sizeof(struct as10x_cmd_header_t)) /* context request types */ -#define GET_CONTEXT_DATA 1 -#define SET_CONTEXT_DATA 2 +#define GET_CONTEXT_DATA 1 +#define SET_CONTEXT_DATA 2 /* ODSP suspend modes */ -#define CFG_MODE_ODSP_RESUME 0 -#define CFG_MODE_ODSP_SUSPEND 1 +#define CFG_MODE_ODSP_RESUME 0 +#define CFG_MODE_ODSP_SUSPEND 1 /* Dump memory size */ -#define DUMP_BLOCK_SIZE_MAX 0x20 +#define DUMP_BLOCK_SIZE_MAX 0x20 /*********************************/ /* TYPE DEFINITION */ /*********************************/ -typedef enum { - CONTROL_PROC_TURNON = 0x0001, - CONTROL_PROC_TURNON_RSP = 0x0100, - CONTROL_PROC_SET_REGISTER = 0x0002, - CONTROL_PROC_SET_REGISTER_RSP = 0x0200, - CONTROL_PROC_GET_REGISTER = 0x0003, - CONTROL_PROC_GET_REGISTER_RSP = 0x0300, - CONTROL_PROC_SETTUNE = 0x000A, - CONTROL_PROC_SETTUNE_RSP = 0x0A00, - CONTROL_PROC_GETTUNESTAT = 0x000B, - CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, - CONTROL_PROC_GETTPS = 0x000D, - CONTROL_PROC_GETTPS_RSP = 0x0D00, - CONTROL_PROC_SETFILTER = 0x000E, - CONTROL_PROC_SETFILTER_RSP = 0x0E00, - CONTROL_PROC_REMOVEFILTER = 0x000F, - CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, - CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, - CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, - CONTROL_PROC_START_STREAMING = 0x0013, - CONTROL_PROC_START_STREAMING_RSP = 0x1300, - CONTROL_PROC_STOP_STREAMING = 0x0014, - CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, - CONTROL_PROC_GET_DEMOD_STATS = 0x0015, - CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, - CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, - CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, - CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, - CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, - CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, - CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, - - CONTROL_PROC_CONTEXT = 0x00FC, - CONTROL_PROC_CONTEXT_RSP = 0xFC00, - CONTROL_PROC_DUMP_MEMORY = 0x00FD, - CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, - CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, - CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, - CONTROL_PROC_TURNOFF = 0x00FF, - CONTROL_PROC_TURNOFF_RSP = 0xFF00 -} control_proc; - - -#pragma pack(1) -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} TURN_ON; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t err; - } rsp; -} TURN_OFF; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* tune params */ - struct as10x_tune_args args; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } rsp; -} SET_TUNE; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* tune status */ - struct as10x_tune_status sts; - } rsp; -} GET_TUNE_STATUS; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* tps details */ - struct as10x_tps tps; - } rsp; -} GET_TPS; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } rsp; -} COMMON; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* PID to filter */ - uint16_t pid; - /* stream type (MPE, PSI/SI or PES )*/ - uint8_t stream_type; - /* PID index in filter table */ - uint8_t idx; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - /* Filter id */ - uint8_t filter_id; - } rsp; -} ADD_PID_FILTER; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* PID to remove */ - uint16_t pid; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* response error */ - uint8_t error; - } rsp; -} DEL_PID_FILTER; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} START_STREAMING; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} STOP_STREAMING; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* demod stats */ - struct as10x_demod_stats stats; - } rsp; -} GET_DEMOD_STATS; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* impulse response ready */ - uint8_t is_ready; - } rsp; -} GET_IMPULSE_RESP; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* value to write (for set context)*/ - struct as10x_register_value reg_val; - /* context tag */ - uint16_t tag; - /* context request type */ - uint16_t type; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* value read (for get context) */ - struct as10x_register_value reg_val; - /* context request type */ - uint16_t type; - /* error */ - uint8_t error; - } rsp; -} FW_CONTEXT; - -typedef union { - /* request */ - struct { - /* response identifier */ - uint16_t proc_id; - /* register description */ - struct as10x_register_addr reg_addr; - /* register content */ - struct as10x_register_value reg_val; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} SET_REGISTER; - -typedef union { - /* request */ - struct { - /* response identifier */ - uint16_t proc_id; - /* register description */ - struct as10x_register_addr reg_addr; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* register content */ - struct as10x_register_value reg_val; - } rsp; -} GET_REGISTER; - -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* mode */ - uint8_t mode; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - } rsp; -} CFG_CHANGE_MODE; +enum control_proc { + CONTROL_PROC_TURNON = 0x0001, + CONTROL_PROC_TURNON_RSP = 0x0100, + CONTROL_PROC_SET_REGISTER = 0x0002, + CONTROL_PROC_SET_REGISTER_RSP = 0x0200, + CONTROL_PROC_GET_REGISTER = 0x0003, + CONTROL_PROC_GET_REGISTER_RSP = 0x0300, + CONTROL_PROC_SETTUNE = 0x000A, + CONTROL_PROC_SETTUNE_RSP = 0x0A00, + CONTROL_PROC_GETTUNESTAT = 0x000B, + CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, + CONTROL_PROC_GETTPS = 0x000D, + CONTROL_PROC_GETTPS_RSP = 0x0D00, + CONTROL_PROC_SETFILTER = 0x000E, + CONTROL_PROC_SETFILTER_RSP = 0x0E00, + CONTROL_PROC_REMOVEFILTER = 0x000F, + CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, + CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, + CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, + CONTROL_PROC_START_STREAMING = 0x0013, + CONTROL_PROC_START_STREAMING_RSP = 0x1300, + CONTROL_PROC_STOP_STREAMING = 0x0014, + CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, + CONTROL_PROC_GET_DEMOD_STATS = 0x0015, + CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, + CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, + CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, + CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, + CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, + CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, + CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, + + CONTROL_PROC_CONTEXT = 0x00FC, + CONTROL_PROC_CONTEXT_RSP = 0xFC00, + CONTROL_PROC_DUMP_MEMORY = 0x00FD, + CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, + CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, + CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, + CONTROL_PROC_TURNOFF = 0x00FF, + CONTROL_PROC_TURNOFF_RSP = 0xFF00 +}; + +union as10x_turn_on { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_turn_off { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t err; + } rsp; +} __packed; + +union as10x_set_tune { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* tune params */ + struct as10x_tune_args args; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_get_tune_status { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tune status */ + struct as10x_tune_status sts; + } rsp; +} __packed; + +union as10x_get_tps { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* tps details */ + struct as10x_tps tps; + } rsp; +} __packed; + +union as10x_common { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_add_pid_filter { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to filter */ + uint16_t pid; + /* stream type (MPE, PSI/SI or PES )*/ + uint8_t stream_type; + /* PID index in filter table */ + uint8_t idx; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + /* Filter id */ + uint8_t filter_id; + } rsp; +} __packed; + +union as10x_del_pid_filter { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* PID to remove */ + uint16_t pid; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* response error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_start_streaming { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_stop_streaming { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_get_demod_stats { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* demod stats */ + struct as10x_demod_stats stats; + } rsp; +} __packed; + +union as10x_get_impulse_resp { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* impulse response ready */ + uint8_t is_ready; + } rsp; +} __packed; + +union as10x_fw_context { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* value to write (for set context)*/ + struct as10x_register_value reg_val; + /* context tag */ + uint16_t tag; + /* context request type */ + uint16_t type; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* value read (for get context) */ + struct as10x_register_value reg_val; + /* context request type */ + uint16_t type; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_set_register { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + /* register content */ + struct as10x_register_value reg_val; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; + +union as10x_get_register { + /* request */ + struct { + /* response identifier */ + uint16_t proc_id; + /* register description */ + struct as10x_register_addr reg_addr; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* register content */ + struct as10x_register_value reg_val; + } rsp; +} __packed; + +union as10x_cfg_change_mode { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* mode */ + uint8_t mode; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + } rsp; +} __packed; struct as10x_cmd_header_t { - uint16_t req_id; - uint16_t prog; - uint16_t version; - uint16_t data_len; -}; + uint16_t req_id; + uint16_t prog; + uint16_t version; + uint16_t data_len; +} __packed; #define DUMP_BLOCK_SIZE 16 -typedef union { - /* request */ - struct { - /* request identifier */ - uint16_t proc_id; - /* dump memory type request */ - uint8_t dump_req; - /* register description */ - struct as10x_register_addr reg_addr; - /* nb blocks to read */ - uint16_t num_blocks; - } req; - /* response */ - struct { - /* response identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* dump response */ - uint8_t dump_rsp; - /* data */ - union { - uint8_t data8[DUMP_BLOCK_SIZE]; - uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; - uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; - } u; - } rsp; -} DUMP_MEMORY; - -typedef union { - struct { - /* request identifier */ - uint16_t proc_id; - /* dump memory type request */ - uint8_t dump_req; - } req; - struct { - /* request identifier */ - uint16_t proc_id; - /* error */ - uint8_t error; - /* dump response */ - uint8_t dump_rsp; - /* dump data */ - uint8_t data[DUMP_BLOCK_SIZE]; - } rsp; -} DUMPLOG_MEMORY; - -typedef union { - /* request */ - struct { - uint16_t proc_id; - uint8_t data[64 - sizeof(struct as10x_cmd_header_t) -2 /* proc_id */]; - } req; - /* response */ - struct { - uint16_t proc_id; - uint8_t error; - uint8_t data[64 - sizeof(struct as10x_cmd_header_t) /* header */ - - 2 /* proc_id */ - 1 /* rc */]; - } rsp; -} RAW_DATA; + +union as10x_dump_memory { + /* request */ + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + /* register description */ + struct as10x_register_addr reg_addr; + /* nb blocks to read */ + uint16_t num_blocks; + } req; + /* response */ + struct { + /* response identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* data */ + union { + uint8_t data8[DUMP_BLOCK_SIZE]; + uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; + uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; + } u; + } rsp; +} __packed; + +union as10x_dumplog_memory { + struct { + /* request identifier */ + uint16_t proc_id; + /* dump memory type request */ + uint8_t dump_req; + } req; + struct { + /* request identifier */ + uint16_t proc_id; + /* error */ + uint8_t error; + /* dump response */ + uint8_t dump_rsp; + /* dump data */ + uint8_t data[DUMP_BLOCK_SIZE]; + } rsp; +} __packed; + +union as10x_raw_data { + /* request */ + struct { + uint16_t proc_id; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) + - 2 /* proc_id */]; + } req; + /* response */ + struct { + uint16_t proc_id; + uint8_t error; + uint8_t data[64 - sizeof(struct as10x_cmd_header_t) + - 2 /* proc_id */ - 1 /* rc */]; + } rsp; +} __packed; struct as10x_cmd_t { - /* header */ - struct as10x_cmd_header_t header; - /* body */ - union { - TURN_ON turn_on; - TURN_OFF turn_off; - SET_TUNE set_tune; - GET_TUNE_STATUS get_tune_status; - GET_TPS get_tps; - COMMON common; - ADD_PID_FILTER add_pid_filter; - DEL_PID_FILTER del_pid_filter; - START_STREAMING start_streaming; - STOP_STREAMING stop_streaming; - GET_DEMOD_STATS get_demod_stats; - GET_IMPULSE_RESP get_impulse_rsp; - FW_CONTEXT context; - SET_REGISTER set_register; - GET_REGISTER get_register; - CFG_CHANGE_MODE cfg_change_mode; - DUMP_MEMORY dump_memory; - DUMPLOG_MEMORY dumplog_memory; - RAW_DATA raw_data; - } body; -}; + struct as10x_cmd_header_t header; + union { + union as10x_turn_on turn_on; + union as10x_turn_off turn_off; + union as10x_set_tune set_tune; + union as10x_get_tune_status get_tune_status; + union as10x_get_tps get_tps; + union as10x_common common; + union as10x_add_pid_filter add_pid_filter; + union as10x_del_pid_filter del_pid_filter; + union as10x_start_streaming start_streaming; + union as10x_stop_streaming stop_streaming; + union as10x_get_demod_stats get_demod_stats; + union as10x_get_impulse_resp get_impulse_rsp; + union as10x_fw_context context; + union as10x_set_register set_register; + union as10x_get_register get_register; + union as10x_cfg_change_mode cfg_change_mode; + union as10x_dump_memory dump_memory; + union as10x_dumplog_memory dumplog_memory; + union as10x_raw_data raw_data; + } body; +} __packed; struct as10x_token_cmd_t { - /* token cmd */ - struct as10x_cmd_t c; - /* token response */ - struct as10x_cmd_t r; -}; -#pragma pack() + /* token cmd */ + struct as10x_cmd_t c; + /* token response */ + struct as10x_cmd_t r; +} __packed; /**************************/ @@ -491,50 +488,42 @@ void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id, uint16_t cmd_len); int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id); -#ifdef __cplusplus -extern "C" { -#endif - /* as10x cmd */ -int as10x_cmd_turn_on(as10x_handle_t *phandle); -int as10x_cmd_turn_off(as10x_handle_t *phandle); +int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap); +int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap); -int as10x_cmd_set_tune(as10x_handle_t *phandle, +int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, struct as10x_tune_args *ptune); -int as10x_cmd_get_tune_status(as10x_handle_t *phandle, +int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, struct as10x_tune_status *pstatus); -int as10x_cmd_get_tps(as10x_handle_t *phandle, +int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps); -int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, +int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, struct as10x_demod_stats *pdemod_stats); -int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, +int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, uint8_t *is_ready); /* as10x cmd stream */ -int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, struct as10x_ts_filter *filter); -int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, uint16_t pid_value); -int as10x_cmd_start_streaming(as10x_handle_t *phandle); -int as10x_cmd_stop_streaming(as10x_handle_t *phandle); +int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap); +int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap); /* as10x cmd cfg */ -int as10x_cmd_set_context(as10x_handle_t *phandle, +int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t value); -int as10x_cmd_get_context(as10x_handle_t *phandle, +int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t *pvalue); -int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode); +int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode); int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id); -#ifdef __cplusplus -} -#endif #endif -/* EOF - vim: set textwidth=80 ts=3 sw=3 sts=3 et: */ diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c index ec6f69fcf399..d2a4bce89623 100644 --- a/drivers/staging/media/as102/as10x_cmd_cfg.c +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c @@ -28,13 +28,13 @@ /** * as10x_cmd_get_context - Send get context command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @tag: context tag * @pvalue: pointer where to store context value read * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, +int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t *pvalue) { int error; @@ -42,11 +42,11 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.context.req)); /* fill command */ @@ -55,14 +55,14 @@ int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) - + HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -87,13 +87,13 @@ out: /** * as10x_cmd_set_context - send set context command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @tag: context tag * @value: value to set in context * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, +int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag, uint32_t value) { int error; @@ -101,11 +101,11 @@ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.context.req)); /* fill command */ @@ -116,14 +116,14 @@ int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, - (uint8_t *) pcmd, - sizeof(pcmd->body.context.req) - + HEADER_SIZE, - (uint8_t *) prsp, - sizeof(prsp->body.context.rsp) - + HEADER_SIZE); + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, + (uint8_t *) pcmd, + sizeof(pcmd->body.context.req) + + HEADER_SIZE, + (uint8_t *) prsp, + sizeof(prsp->body.context.rsp) + + HEADER_SIZE); } else { error = AS10X_CMD_ERROR; } @@ -142,7 +142,7 @@ out: /** * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @mode: mode selected: * - ON : 0x0 => eLNA always ON * - OFF : 0x1 => eLNA always OFF @@ -151,18 +151,18 @@ out: * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) +int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.cfg_change_mode.req)); /* fill command */ @@ -171,8 +171,8 @@ int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) pcmd->body.cfg_change_mode.req.mode = mode; /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.cfg_change_mode.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.cfg_change_mode.rsp) diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c index 045c70683193..6d000f60fb0e 100644 --- a/drivers/staging/media/as102/as10x_cmd_stream.c +++ b/drivers/staging/media/as102/as10x_cmd_stream.c @@ -23,12 +23,12 @@ /** * as10x_cmd_add_PID_filter - send add filter command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * @filter: TSFilter filter for DVB-T * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap, struct as10x_ts_filter *filter) { int error; @@ -36,11 +36,11 @@ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.add_pid_filter.req)); /* fill command */ @@ -55,8 +55,8 @@ int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, pcmd->body.add_pid_filter.req.idx = 0xFF; /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.add_pid_filter.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.add_pid_filter.rsp) @@ -83,12 +83,12 @@ out: /** * as10x_cmd_del_PID_filter - Send delete filter command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapte * @pid_value: PID to delete * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, +int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap, uint16_t pid_value) { int error; @@ -96,11 +96,11 @@ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.del_pid_filter.req)); /* fill command */ @@ -109,8 +109,8 @@ int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.del_pid_filter.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.del_pid_filter.rsp) @@ -132,22 +132,22 @@ out: /** * as10x_cmd_start_streaming - Send start streaming command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_start_streaming(as10x_handle_t *phandle) +int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap) { int error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.start_streaming.req)); /* fill command */ @@ -155,8 +155,8 @@ int as10x_cmd_start_streaming(as10x_handle_t *phandle) cpu_to_le16(CONTROL_PROC_START_STREAMING); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.start_streaming.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.start_streaming.rsp) @@ -178,22 +178,22 @@ out: /** * as10x_cmd_stop_streaming - Send stop streaming command to AS10x - * @phandle: pointer to AS10x handle + * @adap: pointer to AS10x bus adapter * * Return 0 on success or negative value in case of error. */ -int as10x_cmd_stop_streaming(as10x_handle_t *phandle) +int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap) { int8_t error; struct as10x_cmd_t *pcmd, *prsp; ENTER(); - pcmd = phandle->cmd; - prsp = phandle->rsp; + pcmd = adap->cmd; + prsp = adap->rsp; /* prepare command */ - as10x_cmd_build(pcmd, (++phandle->cmd_xid), + as10x_cmd_build(pcmd, (++adap->cmd_xid), sizeof(pcmd->body.stop_streaming.req)); /* fill command */ @@ -201,8 +201,8 @@ int as10x_cmd_stop_streaming(as10x_handle_t *phandle) cpu_to_le16(CONTROL_PROC_STOP_STREAMING); /* send command */ - if (phandle->ops->xfer_cmd) { - error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, + if (adap->ops->xfer_cmd) { + error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, sizeof(pcmd->body.stop_streaming.req) + HEADER_SIZE, (uint8_t *) prsp, sizeof(prsp->body.stop_streaming.rsp) diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h index 4f01a76e9829..62b9795ee424 100644 --- a/drivers/staging/media/as102/as10x_handle.h +++ b/drivers/staging/media/as102/as10x_handle.h @@ -17,41 +17,37 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef __KERNEL__ -struct as102_bus_adapter_t; +struct as10x_bus_adapter_t; struct as102_dev_t; -#define as10x_handle_t struct as102_bus_adapter_t #include "as10x_cmd.h" /* values for "mode" field */ -#define REGMODE8 8 -#define REGMODE16 16 -#define REGMODE32 32 +#define REGMODE8 8 +#define REGMODE16 16 +#define REGMODE32 32 struct as102_priv_ops_t { - int (*upload_fw_pkt) (struct as102_bus_adapter_t *bus_adap, + int (*upload_fw_pkt) (struct as10x_bus_adapter_t *bus_adap, unsigned char *buf, int buflen, int swap32); - int (*send_cmd) (struct as102_bus_adapter_t *bus_adap, + int (*send_cmd) (struct as10x_bus_adapter_t *bus_adap, unsigned char *buf, int buflen); - int (*xfer_cmd) (struct as102_bus_adapter_t *bus_adap, + int (*xfer_cmd) (struct as10x_bus_adapter_t *bus_adap, unsigned char *send_buf, int send_buf_len, unsigned char *recv_buf, int recv_buf_len); -/* - int (*pid_filter) (struct as102_bus_adapter_t *bus_adap, - int index, u16 pid, int onoff); -*/ + int (*start_stream) (struct as102_dev_t *dev); void (*stop_stream) (struct as102_dev_t *dev); - int (*reset_target) (struct as102_bus_adapter_t *bus_adap); + int (*reset_target) (struct as10x_bus_adapter_t *bus_adap); - int (*read_write)(struct as102_bus_adapter_t *bus_adap, uint8_t mode, + int (*read_write)(struct as10x_bus_adapter_t *bus_adap, uint8_t mode, uint32_t rd_addr, uint16_t rd_len, uint32_t wr_addr, uint16_t wr_len); - int (*as102_read_ep2) (struct as102_bus_adapter_t *bus_adap, + int (*as102_read_ep2) (struct as10x_bus_adapter_t *bus_adap, unsigned char *recv_buf, int recv_buf_len); }; diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h index 3dedb3c1420a..fde8140ae88b 100644 --- a/drivers/staging/media/as102/as10x_types.h +++ b/drivers/staging/media/as102/as10x_types.h @@ -26,173 +26,169 @@ /*********************************/ /* bandwidth constant values */ -#define BW_5_MHZ 0x00 -#define BW_6_MHZ 0x01 -#define BW_7_MHZ 0x02 -#define BW_8_MHZ 0x03 +#define BW_5_MHZ 0x00 +#define BW_6_MHZ 0x01 +#define BW_7_MHZ 0x02 +#define BW_8_MHZ 0x03 /* hierarchy priority selection values */ -#define HIER_NO_PRIORITY 0x00 -#define HIER_LOW_PRIORITY 0x01 -#define HIER_HIGH_PRIORITY 0x02 +#define HIER_NO_PRIORITY 0x00 +#define HIER_LOW_PRIORITY 0x01 +#define HIER_HIGH_PRIORITY 0x02 /* constellation available values */ -#define CONST_QPSK 0x00 -#define CONST_QAM16 0x01 -#define CONST_QAM64 0x02 -#define CONST_UNKNOWN 0xFF +#define CONST_QPSK 0x00 +#define CONST_QAM16 0x01 +#define CONST_QAM64 0x02 +#define CONST_UNKNOWN 0xFF /* hierarchy available values */ -#define HIER_NONE 0x00 -#define HIER_ALPHA_1 0x01 -#define HIER_ALPHA_2 0x02 -#define HIER_ALPHA_4 0x03 -#define HIER_UNKNOWN 0xFF +#define HIER_NONE 0x00 +#define HIER_ALPHA_1 0x01 +#define HIER_ALPHA_2 0x02 +#define HIER_ALPHA_4 0x03 +#define HIER_UNKNOWN 0xFF /* interleaving available values */ -#define INTLV_NATIVE 0x00 -#define INTLV_IN_DEPTH 0x01 -#define INTLV_UNKNOWN 0xFF +#define INTLV_NATIVE 0x00 +#define INTLV_IN_DEPTH 0x01 +#define INTLV_UNKNOWN 0xFF /* code rate available values */ -#define CODE_RATE_1_2 0x00 -#define CODE_RATE_2_3 0x01 -#define CODE_RATE_3_4 0x02 -#define CODE_RATE_5_6 0x03 -#define CODE_RATE_7_8 0x04 -#define CODE_RATE_UNKNOWN 0xFF +#define CODE_RATE_1_2 0x00 +#define CODE_RATE_2_3 0x01 +#define CODE_RATE_3_4 0x02 +#define CODE_RATE_5_6 0x03 +#define CODE_RATE_7_8 0x04 +#define CODE_RATE_UNKNOWN 0xFF /* guard interval available values */ -#define GUARD_INT_1_32 0x00 -#define GUARD_INT_1_16 0x01 -#define GUARD_INT_1_8 0x02 -#define GUARD_INT_1_4 0x03 -#define GUARD_UNKNOWN 0xFF +#define GUARD_INT_1_32 0x00 +#define GUARD_INT_1_16 0x01 +#define GUARD_INT_1_8 0x02 +#define GUARD_INT_1_4 0x03 +#define GUARD_UNKNOWN 0xFF /* transmission mode available values */ -#define TRANS_MODE_2K 0x00 -#define TRANS_MODE_8K 0x01 -#define TRANS_MODE_4K 0x02 -#define TRANS_MODE_UNKNOWN 0xFF +#define TRANS_MODE_2K 0x00 +#define TRANS_MODE_8K 0x01 +#define TRANS_MODE_4K 0x02 +#define TRANS_MODE_UNKNOWN 0xFF /* DVBH signalling available values */ -#define TIMESLICING_PRESENT 0x01 -#define MPE_FEC_PRESENT 0x02 +#define TIMESLICING_PRESENT 0x01 +#define MPE_FEC_PRESENT 0x02 /* tune state available */ -#define TUNE_STATUS_NOT_TUNED 0x00 -#define TUNE_STATUS_IDLE 0x01 -#define TUNE_STATUS_LOCKING 0x02 -#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 -#define TUNE_STATUS_STREAM_DETECTED 0x04 -#define TUNE_STATUS_STREAM_TUNED 0x05 -#define TUNE_STATUS_ERROR 0xFF +#define TUNE_STATUS_NOT_TUNED 0x00 +#define TUNE_STATUS_IDLE 0x01 +#define TUNE_STATUS_LOCKING 0x02 +#define TUNE_STATUS_SIGNAL_DVB_OK 0x03 +#define TUNE_STATUS_STREAM_DETECTED 0x04 +#define TUNE_STATUS_STREAM_TUNED 0x05 +#define TUNE_STATUS_ERROR 0xFF /* available TS FID filter types */ -#define TS_PID_TYPE_TS 0 -#define TS_PID_TYPE_PSI_SI 1 -#define TS_PID_TYPE_MPE 2 +#define TS_PID_TYPE_TS 0 +#define TS_PID_TYPE_PSI_SI 1 +#define TS_PID_TYPE_MPE 2 /* number of echos available */ -#define MAX_ECHOS 15 +#define MAX_ECHOS 15 /* Context types */ -#define CONTEXT_LNA 1010 -#define CONTEXT_ELNA_HYSTERESIS 4003 -#define CONTEXT_ELNA_GAIN 4004 -#define CONTEXT_MER_THRESHOLD 5005 -#define CONTEXT_MER_OFFSET 5006 -#define CONTEXT_IR_STATE 7000 -#define CONTEXT_TSOUT_MSB_FIRST 7004 -#define CONTEXT_TSOUT_FALLING_EDGE 7005 +#define CONTEXT_LNA 1010 +#define CONTEXT_ELNA_HYSTERESIS 4003 +#define CONTEXT_ELNA_GAIN 4004 +#define CONTEXT_MER_THRESHOLD 5005 +#define CONTEXT_MER_OFFSET 5006 +#define CONTEXT_IR_STATE 7000 +#define CONTEXT_TSOUT_MSB_FIRST 7004 +#define CONTEXT_TSOUT_FALLING_EDGE 7005 /* Configuration modes */ -#define CFG_MODE_ON 0 -#define CFG_MODE_OFF 1 -#define CFG_MODE_AUTO 2 +#define CFG_MODE_ON 0 +#define CFG_MODE_OFF 1 +#define CFG_MODE_AUTO 2 -#pragma pack(1) struct as10x_tps { - uint8_t constellation; - uint8_t hierarchy; - uint8_t interleaving_mode; - uint8_t code_rate_HP; - uint8_t code_rate_LP; - uint8_t guard_interval; - uint8_t transmission_mode; - uint8_t DVBH_mask_HP; - uint8_t DVBH_mask_LP; - uint16_t cell_ID; -}; + uint8_t modulation; + uint8_t hierarchy; + uint8_t interleaving_mode; + uint8_t code_rate_HP; + uint8_t code_rate_LP; + uint8_t guard_interval; + uint8_t transmission_mode; + uint8_t DVBH_mask_HP; + uint8_t DVBH_mask_LP; + uint16_t cell_ID; +} __packed; struct as10x_tune_args { - /* frequency */ - uint32_t freq; - /* bandwidth */ - uint8_t bandwidth; - /* hierarchy selection */ - uint8_t hier_select; - /* constellation */ - uint8_t constellation; - /* hierarchy */ - uint8_t hierarchy; - /* interleaving mode */ - uint8_t interleaving_mode; - /* code rate */ - uint8_t code_rate; - /* guard interval */ - uint8_t guard_interval; - /* transmission mode */ - uint8_t transmission_mode; -}; + /* frequency */ + uint32_t freq; + /* bandwidth */ + uint8_t bandwidth; + /* hierarchy selection */ + uint8_t hier_select; + /* constellation */ + uint8_t modulation; + /* hierarchy */ + uint8_t hierarchy; + /* interleaving mode */ + uint8_t interleaving_mode; + /* code rate */ + uint8_t code_rate; + /* guard interval */ + uint8_t guard_interval; + /* transmission mode */ + uint8_t transmission_mode; +} __packed; struct as10x_tune_status { - /* tune status */ - uint8_t tune_state; - /* signal strength */ - int16_t signal_strength; - /* packet error rate 10^-4 */ - uint16_t PER; - /* bit error rate 10^-4 */ - uint16_t BER; -}; + /* tune status */ + uint8_t tune_state; + /* signal strength */ + int16_t signal_strength; + /* packet error rate 10^-4 */ + uint16_t PER; + /* bit error rate 10^-4 */ + uint16_t BER; +} __packed; struct as10x_demod_stats { - /* frame counter */ - uint32_t frame_count; - /* Bad frame counter */ - uint32_t bad_frame_count; - /* Number of wrong bytes fixed by Reed-Solomon */ - uint32_t bytes_fixed_by_rs; - /* Averaged MER */ - uint16_t mer; - /* statistics calculation state indicator (started or not) */ - uint8_t has_started; -}; + /* frame counter */ + uint32_t frame_count; + /* Bad frame counter */ + uint32_t bad_frame_count; + /* Number of wrong bytes fixed by Reed-Solomon */ + uint32_t bytes_fixed_by_rs; + /* Averaged MER */ + uint16_t mer; + /* statistics calculation state indicator (started or not) */ + uint8_t has_started; +} __packed; struct as10x_ts_filter { - uint16_t pid; /** valid PID value 0x00 : 0x2000 */ - uint8_t type; /** Red TS_PID_TYPE_<N> values */ - uint8_t idx; /** index in filtering table */ -}; + uint16_t pid; /* valid PID value 0x00 : 0x2000 */ + uint8_t type; /* Red TS_PID_TYPE_<N> values */ + uint8_t idx; /* index in filtering table */ +} __packed; struct as10x_register_value { - uint8_t mode; - union { - uint8_t value8; /* 8 bit value */ - uint16_t value16; /* 16 bit value */ - uint32_t value32; /* 32 bit value */ - }u; -}; - -#pragma pack() + uint8_t mode; + union { + uint8_t value8; /* 8 bit value */ + uint16_t value16; /* 16 bit value */ + uint32_t value32; /* 32 bit value */ + } u; +} __packed; struct as10x_register_addr { - /* register addr */ - uint32_t addr; - /* register mode access */ - uint8_t mode; + /* register addr */ + uint32_t addr; + /* register mode access */ + uint8_t mode; }; - #endif diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 04e93c49f03a..280c84ec4cc2 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -218,9 +218,10 @@ dt3155_start_acq(struct dt3155_priv *pd) * driver-specific callbacks (vb2_ops) */ static int -dt3155_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], - void *alloc_ctxs[]) +dt3155_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) + { struct dt3155_priv *pd = vb2_get_drv_priv(q); void *ret; @@ -262,12 +263,6 @@ dt3155_buf_prepare(struct vb2_buffer *vb) } static int -dt3155_start_streaming(struct vb2_queue *q) -{ - return 0; -} - -static int dt3155_stop_streaming(struct vb2_queue *q) { struct dt3155_priv *pd = vb2_get_drv_priv(q); @@ -308,7 +303,6 @@ const struct vb2_ops q_ops = { .wait_prepare = dt3155_wait_prepare, .wait_finish = dt3155_wait_finish, .buf_prepare = dt3155_buf_prepare, - .start_streaming = dt3155_start_streaming, .stop_streaming = dt3155_stop_streaming, .buf_queue = dt3155_buf_queue, }; @@ -914,9 +908,10 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_req_region; pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0)); - if (!pd->regs) + if (!pd->regs) { err = -ENOMEM; goto err_pci_iomap; + } err = dt3155_init_board(pdev); if (err) goto err_init_board; diff --git a/drivers/staging/media/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h index 7b256a948c27..a007e7442be8 100644 --- a/drivers/staging/media/easycap/easycap.h +++ b/drivers/staging/media/easycap/easycap.h @@ -98,7 +98,6 @@ #define EASYCAP_DRIVER_VERSION "0.9.01" #define EASYCAP_DRIVER_DESCRIPTION "easycapdc60" -#define USB_SKEL_MINOR_BASE 192 #define DONGLE_MANY 8 #define INPUT_MANY 6 /*---------------------------------------------------------------------------*/ @@ -324,8 +323,6 @@ struct easycap { int lost[INPUT_MANY]; int merit[180]; - long long int dnbydt; - int video_interface; int video_altsetting_on; int video_altsetting_off; @@ -353,7 +350,6 @@ struct easycap { u8 *pcache; int video_mt; int audio_mt; - long long audio_bytes; u32 isequence; int vma_many; @@ -450,9 +446,6 @@ struct easycap { * SOUND PROPERTIES */ /*---------------------------------------------------------------------------*/ - - int audio_buffer_many; - int allocation_audio_urb; int allocation_audio_page; int allocation_audio_struct; @@ -469,72 +462,53 @@ struct easycap { * VIDEO FUNCTION PROTOTYPES */ /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ +int easycap_newinput(struct easycap *, int); +void easycap_testcard(struct easycap *, int); +int easycap_isdongle(struct easycap *); + long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long); -int easycap_dqbuf(struct easycap *, int); -int submit_video_urbs(struct easycap *); -int kill_video_urbs(struct easycap *); -int field2frame(struct easycap *); -int redaub(struct easycap *, void *, void *, - int, int, u8, u8, bool); -void easycap_testcard(struct easycap *, int); -int fillin_formats(void); -int newinput(struct easycap *, int); -int adjust_standard(struct easycap *, v4l2_std_id); -int adjust_format(struct easycap *, u32, u32, u32, - int, bool); -int adjust_brightness(struct easycap *, int); -int adjust_contrast(struct easycap *, int); -int adjust_saturation(struct easycap *, int); -int adjust_hue(struct easycap *, int); -int adjust_volume(struct easycap *, int); + +int easycap_video_dqbuf(struct easycap *, int); +int easycap_video_submit_urbs(struct easycap *); +int easycap_video_kill_urbs(struct easycap *); +int easycap_video_fillin_formats(void); + +int adjust_standard(struct easycap *, v4l2_std_id); +int adjust_format(struct easycap *, u32, u32, u32, int, bool); +int adjust_brightness(struct easycap *, int); +int adjust_contrast(struct easycap *, int); +int adjust_saturation(struct easycap *, int); +int adjust_hue(struct easycap *, int); /*---------------------------------------------------------------------------*/ /* * AUDIO FUNCTION PROTOTYPES */ /*---------------------------------------------------------------------------*/ -int easycap_alsa_probe(struct easycap *); -void easycap_alsa_complete(struct urb *); - -int easycap_sound_setup(struct easycap *); -int submit_audio_urbs(struct easycap *); -int kill_audio_urbs(struct easycap *); -void easyoss_testtone(struct easycap *, int); -int audio_setup(struct easycap *); +int easycap_alsa_probe(struct easycap *); +int easycap_audio_kill_urbs(struct easycap *); +void easycap_alsa_complete(struct urb *); /*---------------------------------------------------------------------------*/ /* * LOW-LEVEL FUNCTION PROTOTYPES */ /*---------------------------------------------------------------------------*/ -int audio_gainget(struct usb_device *); -int audio_gainset(struct usb_device *, s8); +int easycap_audio_gainset(struct usb_device *, s8); +int easycap_audio_setup(struct easycap *); -int set_interface(struct usb_device *, u16); -int wakeup_device(struct usb_device *); -int confirm_resolution(struct usb_device *); -int confirm_stream(struct usb_device *); +int easycap_wakeup_device(struct usb_device *); -int setup_stk(struct usb_device *, bool); -int setup_saa(struct usb_device *, bool); -int setup_vt(struct usb_device *); -int check_stk(struct usb_device *, bool); -int check_saa(struct usb_device *, bool); -int ready_saa(struct usb_device *); -int merit_saa(struct usb_device *); -int check_vt(struct usb_device *); -int select_input(struct usb_device *, int, int); -int set_resolution(struct usb_device *, - u16, u16, u16, u16); +int setup_stk(struct usb_device *, bool); +int setup_saa(struct usb_device *, bool); +int ready_saa(struct usb_device *); +int merit_saa(struct usb_device *); +int check_vt(struct usb_device *); +int select_input(struct usb_device *, int, int); +int set_resolution(struct usb_device *, u16, u16, u16, u16); -int read_saa(struct usb_device *, u16); -int read_stk(struct usb_device *, u32); -int write_saa(struct usb_device *, u16, u16); -int write_000(struct usb_device *, u16, u16); -int start_100(struct usb_device *); -int stop_100(struct usb_device *); -int write_300(struct usb_device *); -int read_vt(struct usb_device *, u16); -int write_vt(struct usb_device *, u16, u16); -int isdongle(struct easycap *); +int read_saa(struct usb_device *, u16); +int write_saa(struct usb_device *, u16, u16); +int start_100(struct usb_device *); +int stop_100(struct usb_device *); /*---------------------------------------------------------------------------*/ @@ -588,7 +562,6 @@ extern bool easycap_readback; extern const struct easycap_standard easycap_standard[]; extern struct easycap_format easycap_format[]; extern struct v4l2_queryctrl easycap_control[]; -extern struct usb_driver easycap_usb_driver; extern struct easycap_dongle easycapdc60_dongle[]; #endif /* !__EASYCAP_H__ */ diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c index c99addfb6242..9413b37490c2 100644 --- a/drivers/staging/media/easycap/easycap_ioctl.c +++ b/drivers/staging/media/easycap/easycap_ioctl.c @@ -25,7 +25,6 @@ */ /*****************************************************************************/ -#include <linux/version.h> #include "easycap.h" /*--------------------------------------------------------------------------*/ @@ -125,7 +124,7 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) } if (peasycap->video_isoc_streaming) { resubmit = true; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); } else resubmit = false; /*--------------------------------------------------------------------------*/ @@ -331,7 +330,7 @@ int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id) "from 0x%02X to 0x%02X\n", reg, itwas, isnow); } if (resubmit) - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); return 0; } /*****************************************************************************/ @@ -558,7 +557,7 @@ int adjust_format(struct easycap *peasycap, peasycap->bytesperpixel * peasycap->width * peasycap->height; if (peasycap->video_isoc_streaming) { resubmit = true; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); } else resubmit = false; /*---------------------------------------------------------------------------*/ @@ -622,7 +621,7 @@ int adjust_format(struct easycap *peasycap, } /*---------------------------------------------------------------------------*/ if (resubmit) - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); return peasycap_best_format - easycap_format; } @@ -667,16 +666,15 @@ int adjust_brightness(struct easycap *peasycap, int value) peasycap->inputset[peasycap->input].brightness_ok = 1; } else JOM(8, "%i=peasycap->input\n", peasycap->input); + mood = 0x00FF & (unsigned int)peasycap->brightness; - if (!write_saa(peasycap->pusb_device, 0x0A, mood)) { - SAM("adjusting brightness to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0A, mood)) { SAM("WARNING: failed to adjust brightness " "to 0x%02X\n", mood); return -ENOENT; } - break; + SAM("adjusting brightness to 0x%02X\n", mood); + return 0; } i1++; } @@ -726,15 +724,13 @@ int adjust_contrast(struct easycap *peasycap, int value) JOM(8, "%i=peasycap->input\n", peasycap->input); mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); - if (!write_saa(peasycap->pusb_device, 0x0B, mood)) { - SAM("adjusting contrast to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0B, mood)) { SAM("WARNING: failed to adjust contrast to " "0x%02X\n", mood); return -ENOENT; } - break; + SAM("adjusting contrast to 0x%02X\n", mood); + return 0; } i1++; } @@ -784,14 +780,13 @@ int adjust_saturation(struct easycap *peasycap, int value) } else JOM(8, "%i=peasycap->input\n", peasycap->input); mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); - if (!write_saa(peasycap->pusb_device, 0x0C, mood)) { - SAM("adjusting saturation to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0C, mood)) { SAM("WARNING: failed to adjust saturation to " "0x%02X\n", mood); return -ENOENT; } + SAM("adjusting saturation to 0x%02X\n", mood); + return 0; break; } i1++; @@ -839,13 +834,12 @@ int adjust_hue(struct easycap *peasycap, int value) JOM(8, "%i=peasycap->input\n", peasycap->input); i2 = peasycap->hue - 128; mood = 0x00FF & ((int) i2); - if (!write_saa(peasycap->pusb_device, 0x0D, mood)) { - SAM("adjusting hue to 0x%02X\n", mood); - return 0; - } else { + if (write_saa(peasycap->pusb_device, 0x0D, mood)) { SAM("WARNING: failed to adjust hue to 0x%02X\n", mood); return -ENOENT; } + SAM("adjusting hue to 0x%02X\n", mood); + return 0; break; } i1++; @@ -854,7 +848,7 @@ int adjust_hue(struct easycap *peasycap, int value) return -ENOENT; } /*****************************************************************************/ -int adjust_volume(struct easycap *peasycap, int value) +static int adjust_volume(struct easycap *peasycap, int value) { s8 mood; int i1; @@ -885,15 +879,13 @@ int adjust_volume(struct easycap *peasycap, int value) mood = (16 > peasycap->volume) ? 16 : ((31 < peasycap->volume) ? 31 : (s8) peasycap->volume); - if (!audio_gainset(peasycap->pusb_device, mood)) { - SAM("adjusting volume to 0x%02X\n", mood); - return 0; - } else { + if (!easycap_audio_gainset(peasycap->pusb_device, mood)) { SAM("WARNING: failed to adjust volume to " "0x%2X\n", mood); return -ENOENT; } - break; + SAM("adjusting volume to 0x%02X\n", mood); + return 0; } i1++; } @@ -971,7 +963,7 @@ long easycap_unlocked_ioctl(struct file *file, SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; } - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); if (0 <= kd && DONGLE_MANY > kd) { if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { SAY("ERROR: cannot lock " @@ -986,7 +978,7 @@ long easycap_unlocked_ioctl(struct file *file, * IF NECESSARY, BAIL OUT. */ /*---------------------------------------------------------------------------*/ - if (kd != isdongle(peasycap)) + if (kd != easycap_isdongle(peasycap)) return -ERESTARTSYS; if (!file) { SAY("ERROR: file is NULL\n"); @@ -1226,7 +1218,7 @@ long easycap_unlocked_ioctl(struct file *file, return -EINVAL; } - rc = newinput(peasycap, (int)index); + rc = easycap_newinput(peasycap, (int)index); if (0 == rc) { JOM(8, "newinput(.,%i) OK\n", (int)index); } else { @@ -2209,7 +2201,7 @@ long easycap_unlocked_ioctl(struct file *file, if (!peasycap->polled) { do { - rcdq = easycap_dqbuf(peasycap, 0); + rcdq = easycap_video_dqbuf(peasycap, 0); if (-EIO == rcdq) { JOM(8, "returning -EIO because " "dqbuf() returned -EIO\n"); @@ -2313,7 +2305,7 @@ long easycap_unlocked_ioctl(struct file *file, mutex_unlock(&easycapdc60_dongle[kd].mutex_video); return -EFAULT; } - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); peasycap->video_idle = 0; peasycap->audio_idle = 0; peasycap->video_eof = 0; diff --git a/drivers/staging/media/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c index 0385735ac6df..0380babed22c 100644 --- a/drivers/staging/media/easycap/easycap_low.c +++ b/drivers/staging/media/easycap/easycap_low.c @@ -40,6 +40,7 @@ #include "easycap.h" + #define GET(X, Y, Z) do { \ int __rc; \ *(Z) = (u16)0; \ @@ -59,9 +60,9 @@ /*--------------------------------------------------------------------------*/ static const struct stk1160config { - int reg; - int set; -} stk1160configPAL[256] = { + u16 reg; + u16 set; +} stk1160configPAL[] = { {0x000, 0x0098}, {0x002, 0x0093}, @@ -103,7 +104,7 @@ static const struct stk1160config { {0xFFF, 0xFFFF} }; /*--------------------------------------------------------------------------*/ -static const struct stk1160config stk1160configNTSC[256] = { +static const struct stk1160config stk1160configNTSC[] = { {0x000, 0x0098}, {0x002, 0x0093}, @@ -146,9 +147,9 @@ static const struct stk1160config stk1160configNTSC[256] = { }; /*--------------------------------------------------------------------------*/ static const struct saa7113config { - int reg; - int set; -} saa7113configPAL[256] = { + u8 reg; + u8 set; +} saa7113configPAL[] = { {0x01, 0x08}, {0x02, 0x80}, {0x03, 0x33}, @@ -202,7 +203,7 @@ static const struct saa7113config { {0xFF, 0xFF} }; /*--------------------------------------------------------------------------*/ -static const struct saa7113config saa7113configNTSC[256] = { +static const struct saa7113config saa7113configNTSC[] = { {0x01, 0x08}, {0x02, 0x80}, {0x03, 0x33}, @@ -355,101 +356,6 @@ static int wait_i2c(struct usb_device *p) } /****************************************************************************/ -int confirm_resolution(struct usb_device *p) -{ - u8 get0, get1, get2, get3, get4, get5, get6, get7; - - if (!p) - return -ENODEV; - GET(p, 0x0110, &get0); - GET(p, 0x0111, &get1); - GET(p, 0x0112, &get2); - GET(p, 0x0113, &get3); - GET(p, 0x0114, &get4); - GET(p, 0x0115, &get5); - GET(p, 0x0116, &get6); - GET(p, 0x0117, &get7); - JOT(8, "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - get0, get1, get2, get3, get4, get5, get6, get7); - JOT(8, "....cf PAL_720x526: " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - 0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001); - JOT(8, "....cf PAL_704x526: " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - 0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001); - JOT(8, "....cf VGA_640x480: " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X, " - "0x%03X, 0x%03X\n", - 0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001); - return 0; -} -/****************************************************************************/ -int confirm_stream(struct usb_device *p) -{ - u16 get2; - u8 igot; - - if (!p) - return -ENODEV; - GET(p, 0x0100, &igot); get2 = 0x80 & igot; - if (0x80 == get2) - JOT(8, "confirm_stream: OK\n"); - else - JOT(8, "confirm_stream: STUCK\n"); - return 0; -} -/****************************************************************************/ -int setup_stk(struct usb_device *p, bool ntsc) -{ - int i; - const struct stk1160config *cfg; - if (!p) - return -ENODEV; - cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; - for (i = 0; cfg[i].reg != 0xFFF; i++) - SET(p, cfg[i].reg, cfg[i].set); - - write_300(p); - - return 0; -} -/****************************************************************************/ -int setup_saa(struct usb_device *p, bool ntsc) -{ - int i, ir; - const struct saa7113config *cfg; - if (!p) - return -ENODEV; - cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; - for (i = 0; cfg[i].reg != 0xFF; i++) - ir = write_saa(p, cfg[i].reg, cfg[i].set); - return 0; -} -/****************************************************************************/ -int write_000(struct usb_device *p, u16 set2, u16 set0) -{ - u8 igot0, igot2; - - if (!p) - return -ENODEV; - GET(p, 0x0002, &igot2); - GET(p, 0x0000, &igot0); - SET(p, 0x0002, set2); - SET(p, 0x0000, set0); - return 0; -} -/****************************************************************************/ int write_saa(struct usb_device *p, u16 reg0, u16 set0) { if (!p) @@ -470,8 +376,7 @@ int write_saa(struct usb_device *p, u16 reg0, u16 set0) * REGISTER 504: TARGET ADDRESS ON VT1612A */ /*--------------------------------------------------------------------------*/ -int -write_vt(struct usb_device *p, u16 reg0, u16 set0) +static int write_vt(struct usb_device *p, u16 reg0, u16 set0) { u8 igot; u16 got502, got503; @@ -508,7 +413,7 @@ write_vt(struct usb_device *p, u16 reg0, u16 set0) * REGISTER 504: TARGET ADDRESS ON VT1612A */ /*--------------------------------------------------------------------------*/ -int read_vt(struct usb_device *p, u16 reg0) +static int read_vt(struct usb_device *p, u16 reg0) { u8 igot; u16 got502, got503; @@ -532,7 +437,7 @@ int read_vt(struct usb_device *p, u16 reg0) * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO. */ /*--------------------------------------------------------------------------*/ -int write_300(struct usb_device *p) +static int write_300(struct usb_device *p) { if (!p) return -ENODEV; @@ -545,32 +450,36 @@ int write_300(struct usb_device *p) return 0; } /****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * NOTE: THE FOLLOWING IS NOT CHECKED: - * REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL. - */ -/*--------------------------------------------------------------------------*/ -int check_saa(struct usb_device *p, bool ntsc) +/****************************************************************************/ +int setup_stk(struct usb_device *p, bool ntsc) { - int i, ir, rc = 0; - struct saa7113config const *cfg; + int i; + const struct stk1160config *cfg; if (!p) return -ENODEV; + cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; + for (i = 0; cfg[i].reg != 0xFFF; i++) + SET(p, cfg[i].reg, cfg[i].set); + + write_300(p); - cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; + return 0; +} +/****************************************************************************/ +int setup_saa(struct usb_device *p, bool ntsc) +{ + int i, rc; + const struct saa7113config *cfg; + if (!p) + return -ENODEV; + cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL; for (i = 0; cfg[i].reg != 0xFF; i++) { - if (0x0F == cfg[i].reg) - continue; - ir = read_saa(p, cfg[i].reg); - if (ir != cfg[i].set) { - SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", - cfg[i].reg, ir, cfg[i].set); - rc--; - } + rc = write_saa(p, cfg[i].reg, cfg[i].set); + if (rc) + dev_err(&p->dev, + "Failed to set SAA register %d", cfg[i].reg); } - - return (rc < -8) ? rc : 0; + return 0; } /****************************************************************************/ int merit_saa(struct usb_device *p) @@ -609,60 +518,22 @@ int ready_saa(struct usb_device *p) msleep(marktime); j++; } + if (max == j) return -1; - else { - if (0x20 & rc) { - rate = 2; - JOT(8, "hardware detects 60 Hz\n"); - } else { - rate = 0; - JOT(8, "hardware detects 50 Hz\n"); - } - if (0x80 & rc) - JOT(8, "hardware detects interlacing\n"); - else { - rate++; - JOT(8, "hardware detects no interlacing\n"); - } - } - return 0; -} -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * NOTE: THE FOLLOWING ARE NOT CHECKED: - * REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN - * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config....[.].set) - */ -/*--------------------------------------------------------------------------*/ -int check_stk(struct usb_device *p, bool ntsc) -{ - int i, ir; - const struct stk1160config *cfg; - - if (!p) - return -ENODEV; - cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL; - - for (i = 0; 0xFFF != cfg[i].reg; i++) { - if (0x000 == cfg[i].reg || 0x002 == cfg[i].reg) - continue; - - ir = read_stk(p, cfg[i].reg); - if (0x100 == cfg[i].reg) { - if ((ir != (0xFF & cfg[i].set)) && - (ir != (0x80 | (0xFF & cfg[i].set))) && - (0xFFFF != cfg[i].set)) { - SAY("STK reg[0x%03X]=0x%02X expected 0x%02X\n", - cfg[i].reg, ir, cfg[i].set); - } - continue; - } - if ((ir != (0xFF & cfg[i].set)) && (0xFFFF != cfg[i].set)) - SAY("STK register 0x%03X has 0x%02X,expected 0x%02X\n", - cfg[i].reg, ir, cfg[i].set); + if (0x20 & rc) { + rate = 2; + JOT(8, "hardware detects 60 Hz\n"); + } else { + rate = 0; + JOT(8, "hardware detects 50 Hz\n"); + } + if (0x80 & rc) + JOT(8, "hardware detects interlacing\n"); + else { + rate++; + JOT(8, "hardware detects no interlacing\n"); } return 0; } @@ -682,7 +553,7 @@ int read_saa(struct usb_device *p, u16 reg0) return igot; } /****************************************************************************/ -int read_stk(struct usb_device *p, u32 reg0) +static int read_stk(struct usb_device *p, u32 reg0) { u8 igot; @@ -692,27 +563,7 @@ int read_stk(struct usb_device *p, u32 reg0) GET(p, reg0, &igot); return igot; } -/****************************************************************************/ -/*--------------------------------------------------------------------------*/ -/* - * HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE - * - * CVBS+S-VIDEO 0 or 1 CVBS 1 - * FOUR-CVBS 0 or 1 CVBS1 1 - * FOUR-CVBS 2 CVBS2 2 - * FOUR-CVBS 3 CVBS3 3 - * FOUR-CVBS 4 CVBS4 4 - * CVBS+S-VIDEO 5 S-VIDEO 5 - * - * WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED: - * - * mode 7 => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED) - * mode 9 => USE AUTOMATIC GAIN CONTROL (DEFAULT) - * -*/ -/*---------------------------------------------------------------------------*/ -int -select_input(struct usb_device *p, int input, int mode) +int select_input(struct usb_device *p, int input, int mode) { int ir; @@ -877,10 +728,11 @@ int stop_100(struct usb_device *p) /****************************************************************************/ /****************************************************************************/ /*****************************************************************************/ -int wakeup_device(struct usb_device *pusb_device) +int easycap_wakeup_device(struct usb_device *pusb_device) { if (!pusb_device) return -ENODEV; + return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), USB_REQ_SET_FEATURE, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, @@ -888,8 +740,7 @@ int wakeup_device(struct usb_device *pusb_device) 0, NULL, 0, 50000); } /*****************************************************************************/ -int -audio_setup(struct easycap *peasycap) +int easycap_audio_setup(struct easycap *peasycap) { struct usb_device *pusb_device; u8 buffer[1]; @@ -970,7 +821,7 @@ audio_setup(struct easycap *peasycap) * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN. */ /*---------------------------------------------------------------------------*/ - if (0 != audio_gainset(pusb_device, peasycap->gain)) + if (easycap_audio_gainset(pusb_device, peasycap->gain)) SAY("ERROR: audio_gainset() failed\n"); check_vt(pusb_device); return 0; @@ -1047,7 +898,7 @@ int check_vt(struct usb_device *pusb_device) * 31 12.0 22.5 34.5 */ /*---------------------------------------------------------------------------*/ -int audio_gainset(struct usb_device *pusb_device, s8 loud) +int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud) { int igot; u8 tmp; @@ -1115,15 +966,3 @@ int audio_gainset(struct usb_device *pusb_device, s8 loud) return 0; } /*****************************************************************************/ -int audio_gainget(struct usb_device *pusb_device) -{ - int igot; - - if (!pusb_device) - return -ENODEV; - igot = read_vt(pusb_device, 0x001C); - if (0 > igot) - SAY("ERROR: failed to read VT1612A register 0x1C\n"); - return igot; -} -/*****************************************************************************/ diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c index a45c0b507067..8ff5f38ea196 100644 --- a/drivers/staging/media/easycap/easycap_main.c +++ b/drivers/staging/media/easycap/easycap_main.c @@ -66,6 +66,10 @@ struct easycap_dongle easycapdc60_dongle[DONGLE_MANY]; static struct mutex mutex_dongle; static void easycap_complete(struct urb *purb); static int reset(struct easycap *peasycap); +static int field2frame(struct easycap *peasycap); +static int redaub(struct easycap *peasycap, + void *pad, void *pex, int much, int more, + u8 mask, u8 margin, bool isuy); const char *strerror(int err) { @@ -109,23 +113,13 @@ const char *strerror(int err) #undef ERRNOSTR } -/*---------------------------------------------------------------------------*/ -/* - * PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE - * - * NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY - * CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253. - * THIS IS THE CASE FOR OpenSUSE. - */ -/*---------------------------------------------------------------------------*/ -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ /****************************************************************************/ /*---------------------------------------------------------------------------*/ /* * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap */ /*---------------------------------------------------------------------------*/ -int isdongle(struct easycap *peasycap) +int easycap_isdongle(struct easycap *peasycap) { int k; if (!peasycap) @@ -161,14 +155,13 @@ static int easycap_open(struct inode *inode, struct file *file) if (!peasycap->pusb_device) { SAM("ERROR: peasycap->pusb_device is NULL\n"); return -EFAULT; - } else { - JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device); } + + JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device); + file->private_data = peasycap; - rc = wakeup_device(peasycap->pusb_device); - if (0 == rc) - JOM(8, "wakeup_device() OK\n"); - else { + rc = easycap_wakeup_device(peasycap->pusb_device); + if (rc) { SAM("ERROR: wakeup_device() rc = %i\n", rc); if (-ENODEV == rc) SAM("ERROR: wakeup_device() returned -ENODEV\n"); @@ -176,6 +169,7 @@ static int easycap_open(struct inode *inode, struct file *file) SAM("ERROR: wakeup_device() rc = %i\n", rc); return rc; } + JOM(8, "wakeup_device() OK\n"); peasycap->input = 0; rc = reset(peasycap); if (rc) { @@ -303,7 +297,7 @@ static int reset(struct easycap *peasycap) peasycap->saturation = -8192; peasycap->hue = -8192; - rc = newinput(peasycap, input); + rc = easycap_newinput(peasycap, input); if (rc) { SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input); @@ -364,8 +358,7 @@ static int reset(struct easycap *peasycap) * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE. */ /*---------------------------------------------------------------------------*/ -int -newinput(struct easycap *peasycap, int input) +int easycap_newinput(struct easycap *peasycap, int input) { int rc, k, m, mood, off; int inputnow, video_idlenow, audio_idlenow; @@ -397,7 +390,7 @@ newinput(struct easycap *peasycap, int input) peasycap->audio_idle = 1; if (peasycap->video_isoc_streaming) { resubmit = true; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); } else { resubmit = false; } @@ -532,7 +525,7 @@ newinput(struct easycap *peasycap, int input) return -EFAULT; } if (resubmit) - submit_video_urbs(peasycap); + easycap_video_submit_urbs(peasycap); peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1; peasycap->video_idle = video_idlenow; @@ -542,7 +535,7 @@ newinput(struct easycap *peasycap, int input) return 0; } /*****************************************************************************/ -int submit_video_urbs(struct easycap *peasycap) +int easycap_video_submit_urbs(struct easycap *peasycap) { struct data_urb *pdata_urb; struct urb *purb; @@ -616,43 +609,53 @@ int submit_video_urbs(struct easycap *peasycap) peasycap->video_eof = 1; } - if (isbad) { - JOM(4, "attempting cleanup instead of submitting\n"); - list_for_each(plist_head, (peasycap->purb_video_head)) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - purb = pdata_urb->purb; - if (purb) - usb_kill_urb(purb); - } - } - peasycap->video_isoc_streaming = 0; - } else { + if (isbad) + easycap_video_kill_urbs(peasycap); + else peasycap->video_isoc_streaming = 1; - JOM(4, "submitted %i video urbs\n", m); - } } else { JOM(4, "already streaming video urbs\n"); } return 0; } /*****************************************************************************/ -int kill_video_urbs(struct easycap *peasycap) +int easycap_audio_kill_urbs(struct easycap *peasycap) { int m; struct list_head *plist_head; struct data_urb *pdata_urb; - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); + if (!peasycap->audio_isoc_streaming) + return 0; + + if (!peasycap->purb_audio_head) { + SAM("ERROR: peasycap->purb_audio_head is NULL\n"); return -EFAULT; } - if (!peasycap->video_isoc_streaming) { - JOM(8, "%i=video_isoc_streaming, no video urbs killed\n", - peasycap->video_isoc_streaming); - return 0; + + peasycap->audio_isoc_streaming = 0; + m = 0; + list_for_each(plist_head, peasycap->purb_audio_head) { + pdata_urb = list_entry(plist_head, struct data_urb, list_head); + if (pdata_urb && pdata_urb->purb) { + usb_kill_urb(pdata_urb->purb); + m++; + } } + + JOM(4, "%i audio urbs killed\n", m); + + return 0; +} +int easycap_video_kill_urbs(struct easycap *peasycap) +{ + int m; + struct list_head *plist_head; + struct data_urb *pdata_urb; + + if (!peasycap->video_isoc_streaming) + return 0; + if (!peasycap->purb_video_head) { SAM("ERROR: peasycap->purb_video_head is NULL\n"); return -EFAULT; @@ -690,8 +693,8 @@ static int videodev_release(struct video_device *pvideo_device) SAY("ending unsuccessfully\n"); return -EFAULT; } - if (0 != kill_video_urbs(peasycap)) { - SAM("ERROR: kill_video_urbs() failed\n"); + if (easycap_video_kill_urbs(peasycap)) { + SAM("ERROR: easycap_video_kill_urbs() failed\n"); return -EFAULT; } JOM(4, "ending successfully\n"); @@ -727,27 +730,22 @@ static void easycap_delete(struct kref *pkref) SAM("ERROR: peasycap is NULL: cannot perform deletions\n"); return; } - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); /*---------------------------------------------------------------------------*/ /* * FREE VIDEO. */ /*---------------------------------------------------------------------------*/ if (peasycap->purb_video_head) { - JOM(4, "freeing video urbs\n"); m = 0; - list_for_each(plist_head, (peasycap->purb_video_head)) { + list_for_each(plist_head, peasycap->purb_video_head) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (!pdata_urb) { - JOM(4, "ERROR: pdata_urb is NULL\n"); - } else { - if (pdata_urb->purb) { - usb_free_urb(pdata_urb->purb); - pdata_urb->purb = NULL; - peasycap->allocation_video_urb -= 1; - m++; - } + if (pdata_urb && pdata_urb->purb) { + usb_free_urb(pdata_urb->purb); + pdata_urb->purb = NULL; + peasycap->allocation_video_urb--; + m++; } } @@ -763,7 +761,6 @@ static void easycap_delete(struct kref *pkref) peasycap->allocation_video_struct -= sizeof(struct data_urb); kfree(pdata_urb); - pdata_urb = NULL; m++; } } @@ -828,15 +825,11 @@ static void easycap_delete(struct kref *pkref) list_for_each(plist_head, (peasycap->purb_audio_head)) { pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (!pdata_urb) - JOM(4, "ERROR: pdata_urb is NULL\n"); - else { - if (pdata_urb->purb) { - usb_free_urb(pdata_urb->purb); - pdata_urb->purb = NULL; - peasycap->allocation_audio_urb -= 1; - m++; - } + if (pdata_urb && pdata_urb->purb) { + usb_free_urb(pdata_urb->purb); + pdata_urb->purb = NULL; + peasycap->allocation_audio_urb--; + m++; } } JOM(4, "%i audio urbs freed\n", m); @@ -851,7 +844,6 @@ static void easycap_delete(struct kref *pkref) peasycap->allocation_audio_struct -= sizeof(struct data_urb); kfree(pdata_urb); - pdata_urb = NULL; m++; } } @@ -940,7 +932,7 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait) return -EFAULT; } /*---------------------------------------------------------------------------*/ - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); if (0 <= kd && DONGLE_MANY > kd) { if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd); @@ -952,7 +944,7 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait) * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. * IF NECESSARY, BAIL OUT. */ - if (kd != isdongle(peasycap)) { + if (kd != easycap_isdongle(peasycap)) { mutex_unlock(&easycapdc60_dongle[kd].mutex_video); return -ERESTARTSYS; } @@ -980,21 +972,21 @@ static unsigned int easycap_poll(struct file *file, poll_table *wait) */ return -ERESTARTSYS; /*---------------------------------------------------------------------------*/ - rc = easycap_dqbuf(peasycap, 0); + rc = easycap_video_dqbuf(peasycap, 0); peasycap->polled = 1; mutex_unlock(&easycapdc60_dongle[kd].mutex_video); - if (0 == rc) - return POLLIN | POLLRDNORM; - else + if (rc) return POLLERR; - } + + return POLLIN | POLLRDNORM; +} /*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING. */ /*---------------------------------------------------------------------------*/ -int easycap_dqbuf(struct easycap *peasycap, int mode) +int easycap_video_dqbuf(struct easycap *peasycap, int mode) { int input, ifield, miss, rc; @@ -1080,7 +1072,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) JOM(8, " ... failed returning -EIO\n"); peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); return -EIO; } peasycap->status = 0; @@ -1090,7 +1082,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) #endif /*PERSEVERE*/ peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); JOM(8, "returning -EIO\n"); return -EIO; } @@ -1143,7 +1135,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) JOM(8, " ... failed returning -EIO\n"); peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); return -EIO; } peasycap->status = 0; @@ -1153,7 +1145,7 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) #endif /*PERSEVERE*/ peasycap->video_eof = 1; peasycap->audio_eof = 1; - kill_video_urbs(peasycap); + easycap_video_kill_urbs(peasycap); JOM(8, "returning -EIO\n"); return -EIO; } @@ -1207,12 +1199,9 @@ int easycap_dqbuf(struct easycap *peasycap, int mode) * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH * odd==false IS TRANSFERRED TO THE FRAME BUFFER. * - * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM - * CHOOSES THE OPTION V4L2_FIELD_INTERLACED. */ /*---------------------------------------------------------------------------*/ -int -field2frame(struct easycap *peasycap) +static int field2frame(struct easycap *peasycap) { void *pex, *pad; @@ -1221,7 +1210,7 @@ field2frame(struct easycap *peasycap) int rc, bytesperpixel, multiplier; int much, more, over, rump, caches, input; u8 mask, margin; - bool odd, isuy, decimatepixel, offerfields, badinput; + bool odd, isuy, decimatepixel, badinput; if (!peasycap) { SAY("ERROR: peasycap is NULL\n"); @@ -1237,8 +1226,6 @@ field2frame(struct easycap *peasycap) peasycap->field_buffer[peasycap->field_read][0].input, peasycap->field_read, peasycap->frame_fill); JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel); - if (peasycap->offerfields) - JOM(8, "===== offerfields\n"); /*---------------------------------------------------------------------------*/ /* @@ -1260,7 +1247,6 @@ field2frame(struct easycap *peasycap) #endif /*EASYCAP_TESTCARD*/ /*---------------------------------------------------------------------------*/ - offerfields = peasycap->offerfields; bytesperpixel = peasycap->bytesperpixel; decimatepixel = peasycap->decimatepixel; @@ -1601,9 +1587,9 @@ field2frame(struct easycap *peasycap) * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE. */ /*---------------------------------------------------------------------------*/ -int -redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, - u8 mask, u8 margin, bool isuy) +static int redaub(struct easycap *peasycap, + void *pad, void *pex, int much, int more, + u8 mask, u8 margin, bool isuy) { static s32 ay[256], bu[256], rv[256], gu[256], gv[256]; u8 *pcache; @@ -2855,20 +2841,7 @@ static void easycap_complete(struct urb *purb) } return; } -static const struct file_operations easycap_fops = { - .owner = THIS_MODULE, - .open = easycap_open, - .unlocked_ioctl = easycap_unlocked_ioctl, - .poll = easycap_poll, - .mmap = easycap_mmap, - .llseek = no_llseek, -}; -static const struct usb_class_driver easycap_class = { - .name = "usb/easycap%d", - .fops = &easycap_fops, - .minor_base = USB_SKEL_MINOR_BASE, -}; -/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ + static const struct v4l2_file_operations v4l2_fops = { .owner = THIS_MODULE, .open = easycap_open_noinode, @@ -2917,6 +2890,7 @@ static int easycap_usb_probe(struct usb_interface *intf, SAY("ERROR: usb_host_interface not found\n"); return -EFAULT; } + interface = &alt->desc; if (!interface) { SAY("ERROR: intf_descriptor is NULL\n"); @@ -2976,44 +2950,31 @@ static int easycap_usb_probe(struct usb_interface *intf, if (mutex_lock_interruptible(&mutex_dongle)) { SAY("ERROR: cannot down mutex_dongle\n"); return -ERESTARTSYS; - } else { -/*---------------------------------------------------------------------------*/ - /* - * FOR INTERFACES 1 AND 2 THE POINTER peasycap WILL NEED TO - * TO BE THE SAME AS THAT ALLOCATED NOW FOR INTERFACE 0. - * - * NORMALLY ndong WILL NOT HAVE CHANGED SINCE INTERFACE 0 WAS - * PROBED, BUT THIS MAY NOT BE THE CASE IF, FOR EXAMPLE, TWO - * EASYCAPs ARE PLUGGED IN SIMULTANEOUSLY. - */ -/*---------------------------------------------------------------------------*/ - for (ndong = 0; ndong < DONGLE_MANY; ndong++) { - if ((!easycapdc60_dongle[ndong].peasycap) && - (!mutex_is_locked(&easycapdc60_dongle - [ndong].mutex_video)) && - (!mutex_is_locked(&easycapdc60_dongle - [ndong].mutex_audio))) { - easycapdc60_dongle[ndong].peasycap = peasycap; - peasycap->isdongle = ndong; - JOM(8, "intf[%i]: peasycap-->easycap" - "_dongle[%i].peasycap\n", - bInterfaceNumber, ndong); - break; - } - } - if (DONGLE_MANY <= ndong) { - SAM("ERROR: too many dongles\n"); - mutex_unlock(&mutex_dongle); - return -ENOMEM; + } + + for (ndong = 0; ndong < DONGLE_MANY; ndong++) { + if ((!easycapdc60_dongle[ndong].peasycap) && + (!mutex_is_locked(&easycapdc60_dongle + [ndong].mutex_video)) && + (!mutex_is_locked(&easycapdc60_dongle + [ndong].mutex_audio))) { + easycapdc60_dongle[ndong].peasycap = peasycap; + peasycap->isdongle = ndong; + JOM(8, "intf[%i]: peasycap-->easycap" + "_dongle[%i].peasycap\n", + bInterfaceNumber, ndong); + break; } + } + + if (DONGLE_MANY <= ndong) { + SAM("ERROR: too many dongles\n"); mutex_unlock(&mutex_dongle); + return -ENOMEM; } + mutex_unlock(&mutex_dongle); + peasycap->allocation_video_struct = sizeof(struct easycap); - peasycap->allocation_video_page = 0; - peasycap->allocation_video_urb = 0; - peasycap->allocation_audio_struct = 0; - peasycap->allocation_audio_page = 0; - peasycap->allocation_audio_urb = 0; /*---------------------------------------------------------------------------*/ /* @@ -3023,7 +2984,6 @@ static int easycap_usb_probe(struct usb_interface *intf, peasycap->pusb_device = usbdev; peasycap->pusb_interface = intf; - peasycap->ilk = 0; peasycap->microphone = false; peasycap->video_interface = -1; @@ -3042,38 +3002,21 @@ static int easycap_usb_probe(struct usb_interface *intf, peasycap->frame_buffer_many = FRAME_BUFFER_MANY; - for (k = 0; k < INPUT_MANY; k++) - peasycap->lost[k] = 0; - peasycap->skip = 0; - peasycap->skipped = 0; - peasycap->offerfields = 0; /*---------------------------------------------------------------------------*/ /* * DYNAMICALLY FILL IN THE AVAILABLE FORMATS ... */ /*---------------------------------------------------------------------------*/ - rc = fillin_formats(); + rc = easycap_video_fillin_formats(); if (0 > rc) { SAM("ERROR: fillin_formats() rc = %i\n", rc); return -EFAULT; } JOM(4, "%i formats available\n", rc); -/*---------------------------------------------------------------------------*/ -/* - * ... AND POPULATE easycap.inputset[] -*/ -/*---------------------------------------------------------------------------*/ - /* FIXME: maybe we just use memset 0 */ + + /* ... AND POPULATE easycap.inputset[] */ + inputset = peasycap->inputset; - for (k = 0; k < INPUT_MANY; k++) { - inputset[k].input_ok = 0; - inputset[k].standard_offset_ok = 0; - inputset[k].format_offset_ok = 0; - inputset[k].brightness_ok = 0; - inputset[k].contrast_ok = 0; - inputset[k].saturation_ok = 0; - inputset[k].hue_ok = 0; - } fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN; m = 0; @@ -3390,11 +3333,10 @@ static int easycap_usb_probe(struct usb_interface *intf, if (!isokalt) { SAM("ERROR: no viable video_altsetting_on\n"); return -ENOENT; - } else { - peasycap->video_altsetting_on = okalt[isokalt - 1]; - JOM(4, "%i=video_altsetting_on <====\n", - peasycap->video_altsetting_on); } + peasycap->video_altsetting_on = okalt[isokalt - 1]; + JOM(4, "%i=video_altsetting_on <====\n", + peasycap->video_altsetting_on); /*---------------------------------------------------------------------------*/ /* * DECIDE THE VIDEO STREAMING PARAMETERS @@ -3480,8 +3422,9 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate frame " "buffer %i page %i\n", k, m); return -ENOMEM; - } else - peasycap->allocation_video_page += 1; + } + + peasycap->allocation_video_page += 1; peasycap->frame_buffer[k][m].pgo = pbuf; } peasycap->frame_buffer[k][m].pto = @@ -3510,11 +3453,11 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate field" " buffer %i page %i\n", k, m); return -ENOMEM; - } - else - peasycap->allocation_video_page += 1; - peasycap->field_buffer[k][m].pgo = pbuf; } + + peasycap->allocation_video_page += 1; + peasycap->field_buffer[k][m].pgo = pbuf; + } peasycap->field_buffer[k][m].pto = peasycap->field_buffer[k][m].pgo; } @@ -3538,9 +3481,9 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate isoc video buffer " "%i\n", k); return -ENOMEM; - } else - peasycap->allocation_video_page += - BIT(VIDEO_ISOC_ORDER); + } + peasycap->allocation_video_page += + BIT(VIDEO_ISOC_ORDER); peasycap->video_isoc_buffer[k].pgo = pbuf; peasycap->video_isoc_buffer[k].pto = @@ -3569,15 +3512,17 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: usb_alloc_urb returned NULL for buffer " "%i\n", k); return -ENOMEM; - } else - peasycap->allocation_video_urb += 1; + } + + peasycap->allocation_video_urb += 1; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); if (!pdata_urb) { SAM("ERROR: Could not allocate struct data_urb.\n"); return -ENOMEM; - } else - peasycap->allocation_video_struct += + } + + peasycap->allocation_video_struct += sizeof(struct data_urb); pdata_urb->purb = purb; @@ -3694,13 +3639,12 @@ static int easycap_usb_probe(struct usb_interface *intf, err("Not able to register with videodev"); videodev_release(&(peasycap->video_device)); return -ENODEV; - } else { - (peasycap->registered_video)++; - SAM("registered with videodev: %i=minor\n", - peasycap->video_device.minor); - peasycap->minor = peasycap->video_device.minor; } -/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ + + peasycap->registered_video++; + SAM("registered with videodev: %i=minor\n", + peasycap->video_device.minor); + peasycap->minor = peasycap->video_device.minor; break; } @@ -3734,11 +3678,10 @@ static int easycap_usb_probe(struct usb_interface *intf, if (!isokalt) { SAM("ERROR: no viable audio_altsetting_on\n"); return -ENOENT; - } else { - peasycap->audio_altsetting_on = okalt[isokalt - 1]; - JOM(4, "%i=audio_altsetting_on <====\n", - peasycap->audio_altsetting_on); } + peasycap->audio_altsetting_on = okalt[isokalt - 1]; + JOM(4, "%i=audio_altsetting_on <====\n", + peasycap->audio_altsetting_on); peasycap->audio_endpointnumber = okepn[isokalt - 1]; JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber); @@ -3847,8 +3790,8 @@ static int easycap_usb_probe(struct usb_interface *intf, SAM("ERROR: Could not allocate isoc audio buffer " "%i\n", k); return -ENOMEM; - } else - peasycap->allocation_audio_page += + } + peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER); peasycap->audio_isoc_buffer[k].pgo = pbuf; @@ -3996,12 +3939,9 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface) { struct usb_host_interface *pusb_host_interface; struct usb_interface_descriptor *pusb_interface_descriptor; - u8 bInterfaceNumber; struct easycap *peasycap; - - struct list_head *plist_head; - struct data_urb *pdata_urb; - int minor, m, kd; + int minor, kd; + u8 bInterfaceNumber; JOT(4, "\n"); @@ -4036,45 +3976,14 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface) peasycap->audio_eof = 1; wake_up_interruptible(&(peasycap->wq_video)); wake_up_interruptible(&(peasycap->wq_audio)); -/*---------------------------------------------------------------------------*/ + switch (bInterfaceNumber) { - case 0: { - if (peasycap->purb_video_head) { - JOM(4, "killing video urbs\n"); - m = 0; - list_for_each(plist_head, peasycap->purb_video_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - if (pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - } - JOM(4, "%i video urbs killed\n", m); - } + case 0: + easycap_video_kill_urbs(peasycap); break; - } -/*---------------------------------------------------------------------------*/ - case 2: { - if (peasycap->purb_audio_head) { - JOM(4, "killing audio urbs\n"); - m = 0; - list_for_each(plist_head, peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, - struct data_urb, list_head); - if (pdata_urb) { - if (pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - } - JOM(4, "%i audio urbs killed\n", m); - } + case 2: + easycap_audio_kill_urbs(peasycap); break; - } default: break; } @@ -4087,7 +3996,7 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface) * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE. */ /*--------------------------------------------------------------------------*/ - kd = isdongle(peasycap); + kd = easycap_isdongle(peasycap); switch (bInterfaceNumber) { case 0: { if (0 <= kd && DONGLE_MANY > kd) { @@ -4212,7 +4121,7 @@ static struct usb_device_id easycap_usb_device_id_table[] = { }; MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table); -struct usb_driver easycap_usb_driver = { +static struct usb_driver easycap_usb_driver = { .name = "easycap", .id_table = easycap_usb_device_id_table, .probe = easycap_usb_probe, diff --git a/drivers/staging/media/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c index 70f59b13c34d..3f5f5b3e5a35 100644 --- a/drivers/staging/media/easycap/easycap_settings.c +++ b/drivers/staging/media/easycap/easycap_settings.c @@ -313,7 +313,7 @@ const struct easycap_standard easycap_standard[] = { struct easycap_format easycap_format[1 + SETTINGS_MANY]; -int fillin_formats(void) +int easycap_video_fillin_formats(void) { const char *name1, *name2, *name3, *name4; struct v4l2_format *fmt; diff --git a/drivers/staging/media/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c index b22bb39b5f69..8c8bcae8ded8 100644 --- a/drivers/staging/media/easycap/easycap_sound.c +++ b/drivers/staging/media/easycap/easycap_sound.c @@ -56,6 +56,141 @@ static const struct snd_pcm_hardware alsa_hardware = { }; +/*---------------------------------------------------------------------------*/ +/* + * SUBMIT ALL AUDIO URBS. + */ +/*---------------------------------------------------------------------------*/ +static int easycap_audio_submit_urbs(struct easycap *peasycap) +{ + struct data_urb *pdata_urb; + struct urb *purb; + struct list_head *plist_head; + int j, isbad, nospc, m, rc; + int isbuf; + + if (!peasycap->purb_audio_head) { + SAM("ERROR: peasycap->urb_audio_head uninitialized\n"); + return -EFAULT; + } + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -EFAULT; + } + + if (peasycap->audio_isoc_streaming) { + JOM(4, "already streaming audio urbs\n"); + return 0; + } + + JOM(4, "initial submission of all audio urbs\n"); + rc = usb_set_interface(peasycap->pusb_device, + peasycap->audio_interface, + peasycap->audio_altsetting_on); + JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", + peasycap->audio_interface, + peasycap->audio_altsetting_on, rc); + + isbad = 0; + nospc = 0; + m = 0; + list_for_each(plist_head, peasycap->purb_audio_head) { + pdata_urb = list_entry(plist_head, struct data_urb, list_head); + if (pdata_urb && pdata_urb->purb) { + purb = pdata_urb->purb; + isbuf = pdata_urb->isbuf; + + purb->interval = 1; + purb->dev = peasycap->pusb_device; + purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, + peasycap->audio_endpointnumber); + purb->transfer_flags = URB_ISO_ASAP; + purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo; + purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size; + purb->complete = easycap_alsa_complete; + purb->context = peasycap; + purb->start_frame = 0; + purb->number_of_packets = peasycap->audio_isoc_framesperdesc; + for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) { + purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize; + purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize; + } + + rc = usb_submit_urb(purb, GFP_KERNEL); + if (rc) { + isbad++; + SAM("ERROR: usb_submit_urb() failed" + " for urb with rc: -%s: %d\n", + strerror(rc), rc); + } else { + m++; + } + } else { + isbad++; + } + } + if (nospc) { + SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); + SAM("..... possibly inadequate USB bandwidth\n"); + peasycap->audio_eof = 1; + } + + if (isbad) + easycap_audio_kill_urbs(peasycap); + else + peasycap->audio_isoc_streaming = m; + + return 0; +} +/*---------------------------------------------------------------------------*/ +/* + * COMMON AUDIO INITIALIZATION + */ +/*---------------------------------------------------------------------------*/ +static int easycap_sound_setup(struct easycap *peasycap) +{ + int rc; + + JOM(4, "starting initialization\n"); + + if (!peasycap) { + SAY("ERROR: peasycap is NULL.\n"); + return -EFAULT; + } + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device is NULL\n"); + return -ENODEV; + } + JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); + + rc = easycap_audio_setup(peasycap); + JOM(8, "audio_setup() returned %i\n", rc); + + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device has become NULL\n"); + return -ENODEV; + } +/*---------------------------------------------------------------------------*/ + if (!peasycap->pusb_device) { + SAM("ERROR: peasycap->pusb_device has become NULL\n"); + return -ENODEV; + } + rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, + peasycap->audio_altsetting_on); + JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, + peasycap->audio_altsetting_on, rc); + + rc = easycap_wakeup_device(peasycap->pusb_device); + JOM(8, "wakeup_device() returned %i\n", rc); + + peasycap->audio_eof = 0; + peasycap->audio_idle = 0; + + easycap_audio_submit_urbs(peasycap); + + JOM(4, "finished initialization\n"); + return 0; +} /*****************************************************************************/ /*---------------------------------------------------------------------------*/ /* @@ -64,8 +199,7 @@ static const struct snd_pcm_hardware alsa_hardware = { * IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO. */ /*---------------------------------------------------------------------------*/ -void -easycap_alsa_complete(struct urb *purb) +void easycap_alsa_complete(struct urb *purb) { struct easycap *peasycap; struct snd_pcm_substream *pss; @@ -458,7 +592,6 @@ static int easycap_alsa_ack(struct snd_pcm_substream *pss) static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd) { struct easycap *peasycap; - int retval; JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START, SNDRV_PCM_TRIGGER_STOP); @@ -481,7 +614,7 @@ static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd) break; } default: - retval = -EINVAL; + return -EINVAL; } return 0; } @@ -615,202 +748,3 @@ int easycap_alsa_probe(struct easycap *peasycap) return 0; } -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * COMMON AUDIO INITIALIZATION - */ -/*---------------------------------------------------------------------------*/ -int -easycap_sound_setup(struct easycap *peasycap) -{ - int rc; - - JOM(4, "starting initialization\n"); - - if (!peasycap) { - SAY("ERROR: peasycap is NULL.\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -ENODEV; - } - JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device); - - rc = audio_setup(peasycap); - JOM(8, "audio_setup() returned %i\n", rc); - - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -ENODEV; - } -/*---------------------------------------------------------------------------*/ - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device has become NULL\n"); - return -ENODEV; - } - rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, - peasycap->audio_altsetting_on); - JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, - peasycap->audio_altsetting_on, rc); - - rc = wakeup_device(peasycap->pusb_device); - JOM(8, "wakeup_device() returned %i\n", rc); - - peasycap->audio_eof = 0; - peasycap->audio_idle = 0; - - submit_audio_urbs(peasycap); - - JOM(4, "finished initialization\n"); - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * SUBMIT ALL AUDIO URBS. - */ -/*---------------------------------------------------------------------------*/ -int -submit_audio_urbs(struct easycap *peasycap) -{ - struct data_urb *pdata_urb; - struct urb *purb; - struct list_head *plist_head; - int j, isbad, nospc, m, rc; - int isbuf; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - if (!peasycap->purb_audio_head) { - SAM("ERROR: peasycap->urb_audio_head uninitialized\n"); - return -EFAULT; - } - if (!peasycap->pusb_device) { - SAM("ERROR: peasycap->pusb_device is NULL\n"); - return -EFAULT; - } - - if (peasycap->audio_isoc_streaming) { - JOM(4, "already streaming audio urbs\n"); - return 0; - } - - JOM(4, "initial submission of all audio urbs\n"); - rc = usb_set_interface(peasycap->pusb_device, - peasycap->audio_interface, - peasycap->audio_altsetting_on); - JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", - peasycap->audio_interface, - peasycap->audio_altsetting_on, rc); - - isbad = 0; - nospc = 0; - m = 0; - list_for_each(plist_head, peasycap->purb_audio_head) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - purb = pdata_urb->purb; - isbuf = pdata_urb->isbuf; - - purb->interval = 1; - purb->dev = peasycap->pusb_device; - purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, - peasycap->audio_endpointnumber); - purb->transfer_flags = URB_ISO_ASAP; - purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo; - purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size; - purb->complete = easycap_alsa_complete; - purb->context = peasycap; - purb->start_frame = 0; - purb->number_of_packets = peasycap->audio_isoc_framesperdesc; - for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) { - purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize; - purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize; - } - - rc = usb_submit_urb(purb, GFP_KERNEL); - if (rc) { - isbad++; - SAM("ERROR: usb_submit_urb() failed" - " for urb with rc: -%s: %d\n", - strerror(rc), rc); - } else { - m++; - } - } else { - isbad++; - } - } - if (nospc) { - SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc); - SAM("..... possibly inadequate USB bandwidth\n"); - peasycap->audio_eof = 1; - } - if (isbad) { - JOM(4, "attempting cleanup instead of submitting\n"); - list_for_each(plist_head, (peasycap->purb_audio_head)) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) - usb_kill_urb(pdata_urb->purb); - } - peasycap->audio_isoc_streaming = 0; - } else { - peasycap->audio_isoc_streaming = m; - JOM(4, "submitted %i audio urbs\n", m); - } - - return 0; -} -/*****************************************************************************/ -/*---------------------------------------------------------------------------*/ -/* - * KILL ALL AUDIO URBS. - */ -/*---------------------------------------------------------------------------*/ -int -kill_audio_urbs(struct easycap *peasycap) -{ - int m; - struct list_head *plist_head; - struct data_urb *pdata_urb; - - if (!peasycap) { - SAY("ERROR: peasycap is NULL\n"); - return -EFAULT; - } - - if (!peasycap->audio_isoc_streaming) { - JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n", - peasycap->audio_isoc_streaming); - return 0; - } - - if (!peasycap->purb_audio_head) { - SAM("ERROR: peasycap->purb_audio_head is NULL\n"); - return -EFAULT; - } - - peasycap->audio_isoc_streaming = 0; - JOM(4, "killing audio urbs\n"); - m = 0; - list_for_each(plist_head, (peasycap->purb_audio_head)) { - pdata_urb = list_entry(plist_head, struct data_urb, list_head); - if (pdata_urb && pdata_urb->purb) { - usb_kill_urb(pdata_urb->purb); - m++; - } - } - JOM(4, "%i audio urbs killed\n", m); - - return 0; -} -/*****************************************************************************/ diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index b7175fe1b15f..70e006b50f29 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1054,7 +1054,13 @@ static int go7007_usb_probe(struct usb_interface *intf, else go->hpi_ops = &go7007_usb_onboard_hpi_ops; go->hpi_context = usb; - usb_fill_int_urb(usb->intr_urb, usb->usbdev, + if (go->board_id == GO7007_BOARDID_SENSORAY_2250) + usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, + usb_rcvbulkpipe(usb->usbdev, 4), + usb->intr_urb->transfer_buffer, 2*sizeof(u16), + go7007_usb_readinterrupt_complete, go); + else + usb_fill_int_urb(usb->intr_urb, usb->usbdev, usb_rcvintpipe(usb->usbdev, 4), usb->intr_urb->transfer_buffer, 2*sizeof(u16), go7007_usb_readinterrupt_complete, go, 8); diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c index deac938d8505..d071c838ac2a 100644 --- a/drivers/staging/media/go7007/snd-go7007.c +++ b/drivers/staging/media/go7007/snd-go7007.c @@ -38,7 +38,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; module_param_array(index, int, NULL, 0444); module_param_array(id, charp, NULL, 0444); diff --git a/drivers/staging/media/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c index c5a0d27a02dc..4d20e9f74118 100644 --- a/drivers/staging/media/lirc/lirc_bt829.c +++ b/drivers/staging/media/lirc/lirc_bt829.c @@ -53,7 +53,7 @@ static unsigned char do_get_bits(void); #define DRIVER_NAME "lirc_bt829" -static int debug; +static bool debug; #define dprintk(fmt, args...) \ do { \ if (debug) \ diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c index 6cd4cd67a1dd..7a2501776679 100644 --- a/drivers/staging/media/lirc/lirc_igorplugusb.c +++ b/drivers/staging/media/lirc/lirc_igorplugusb.c @@ -62,9 +62,9 @@ /* debugging support */ #ifdef CONFIG_USB_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif #define dprintk(fmt, args...) \ diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c index f68218012f23..5f7f8cd3a661 100644 --- a/drivers/staging/media/lirc/lirc_imon.c +++ b/drivers/staging/media/lirc/lirc_imon.c @@ -63,7 +63,7 @@ static int display_open(struct inode *inode, struct file *file); static int display_close(struct inode *inode, struct file *file); /* VFD write operation */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos); /* LIRC driver function prototypes */ @@ -369,7 +369,7 @@ static int send_packet(struct imon_context *context) * than 32 bytes are provided spaces will be appended to * generate a full screen. */ -static ssize_t vfd_write(struct file *file, const char *buf, +static ssize_t vfd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int i; diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c index 792aac0a8e7b..dd2bca7b56fa 100644 --- a/drivers/staging/media/lirc/lirc_parallel.c +++ b/drivers/staging/media/lirc/lirc_parallel.c @@ -63,8 +63,8 @@ /*** Global Variables ***/ -static int debug; -static int check_pselecd; +static bool debug; +static bool check_pselecd; unsigned int irq = LIRC_IRQ; unsigned int io = LIRC_PORT; @@ -752,4 +752,4 @@ module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging messages"); module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); +MODULE_PARM_DESC(check_pselecd, "Check for printer (default: 0)"); diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 8a060a8a7224..8dd8897ad860 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -107,13 +107,13 @@ struct lirc_serial { static int type; static int io; static int irq; -static int iommap; +static bool iommap; static int ioshift; -static int softcarrier = 1; -static int share_irq; -static int debug; +static bool softcarrier = 1; +static bool share_irq; +static bool debug; static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -static int txsense; /* 0 = active high, 1 = active low */ +static bool txsense; /* 0 = active high, 1 = active low */ #define dprintk(fmt, args...) \ do { \ @@ -773,7 +773,7 @@ static int hardware_init_port(void) /* we fail, there's nothing here */ printk(KERN_ERR LIRC_DRIVER_NAME ": port existence test " "failed, cannot continue\n"); - return -EINVAL; + return -ENODEV; } @@ -836,25 +836,22 @@ static int hardware_init_port(void) return 0; } -static int init_port(void) +static int __devinit lirc_serial_probe(struct platform_device *dev) { int i, nlow, nhigh, result; result = request_irq(irq, irq_handler, (share_irq ? IRQF_SHARED : 0), LIRC_DRIVER_NAME, (void *)&hardware); - - switch (result) { - case -EBUSY: - printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq); - return -EBUSY; - case -EINVAL: - printk(KERN_ERR LIRC_DRIVER_NAME - ": Bad irq number or handler\n"); - return -EINVAL; - default: - break; - }; + if (result < 0) { + if (result == -EBUSY) + printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", + irq); + else if (result == -EINVAL) + printk(KERN_ERR LIRC_DRIVER_NAME + ": Bad irq number or handler\n"); + return result; + } /* Reserve io region. */ /* @@ -875,11 +872,13 @@ static int init_port(void) ": or compile the serial port driver as module and\n"); printk(KERN_WARNING LIRC_DRIVER_NAME ": make sure this module is loaded first\n"); - return -EBUSY; + result = -EBUSY; + goto exit_free_irq; } - if (hardware_init_port() < 0) - return -EINVAL; + result = hardware_init_port(); + if (result < 0) + goto exit_release_region; /* Initialize pulse/space widths */ init_timing_params(duty_cycle, freq); @@ -911,6 +910,28 @@ static int init_port(void) dprintk("Interrupt %d, port %04x obtained\n", irq, io); return 0; + +exit_release_region: + if (iommap != 0) + release_mem_region(iommap, 8 << ioshift); + else + release_region(io, 8); +exit_free_irq: + free_irq(irq, (void *)&hardware); + + return result; +} + +static int __devexit lirc_serial_remove(struct platform_device *dev) +{ + free_irq(irq, (void *)&hardware); + + if (iommap != 0) + release_mem_region(iommap, 8 << ioshift); + else + release_region(io, 8); + + return 0; } static int set_use_inc(void *data) @@ -955,7 +976,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, int *wbuf; if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) - return -EBADF; + return -EPERM; count = n / sizeof(int); if (n % sizeof(int) || count % 2 == 0) @@ -1006,11 +1027,11 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) return result; /* only LIRC_MODE_PULSE supported */ if (value != LIRC_MODE_PULSE) - return -ENOSYS; + return -EINVAL; break; case LIRC_GET_LENGTH: - return -ENOSYS; + return -ENOIOCTLCMD; break; case LIRC_SET_SEND_DUTY_CYCLE: @@ -1076,16 +1097,6 @@ static struct lirc_driver driver = { static struct platform_device *lirc_serial_dev; -static int __devinit lirc_serial_probe(struct platform_device *dev) -{ - return 0; -} - -static int __devexit lirc_serial_remove(struct platform_device *dev) -{ - return 0; -} - static int lirc_serial_suspend(struct platform_device *dev, pm_message_t state) { @@ -1111,11 +1122,11 @@ static void lirc_serial_exit(void); static int lirc_serial_resume(struct platform_device *dev) { unsigned long flags; + int result; - if (hardware_init_port() < 0) { - lirc_serial_exit(); - return -EINVAL; - } + result = hardware_init_port(); + if (result < 0) + return result; spin_lock_irqsave(&hardware[type].lock, flags); /* Enable Interrupt */ @@ -1148,7 +1159,7 @@ static int __init lirc_serial_init(void) /* Init read buffer. */ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); if (result < 0) - return -ENOMEM; + return result; result = platform_driver_register(&lirc_serial_driver); if (result) { @@ -1188,10 +1199,6 @@ static int __init lirc_serial_init_module(void) { int result; - result = lirc_serial_init(); - if (result) - return result; - switch (type) { case LIRC_HOMEBREW: case LIRC_IRDEO: @@ -1211,8 +1218,7 @@ static int __init lirc_serial_init_module(void) break; #endif default: - result = -EINVAL; - goto exit_serial_exit; + return -EINVAL; } if (!softcarrier) { switch (type) { @@ -1228,37 +1234,26 @@ static int __init lirc_serial_init_module(void) } } - result = init_port(); - if (result < 0) - goto exit_serial_exit; + result = lirc_serial_init(); + if (result) + return result; + driver.features = hardware[type].features; driver.dev = &lirc_serial_dev->dev; driver.minor = lirc_register_driver(&driver); if (driver.minor < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": register_chrdev failed!\n"); - result = -EIO; - goto exit_release; + lirc_serial_exit(); + return driver.minor; } return 0; -exit_release: - release_region(io, 8); -exit_serial_exit: - lirc_serial_exit(); - return result; } static void __exit lirc_serial_exit_module(void) { - lirc_serial_exit(); - - free_irq(irq, (void *)&hardware); - - if (iommap != 0) - release_mem_region(iommap, 8 << ioshift); - else - release_region(io, 8); lirc_unregister_driver(driver.minor); + lirc_serial_exit(); dprintk("cleaned up module\n"); } diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c index 6903d3992eca..c94382b917ac 100644 --- a/drivers/staging/media/lirc/lirc_sir.c +++ b/drivers/staging/media/lirc/lirc_sir.c @@ -173,7 +173,7 @@ static DEFINE_SPINLOCK(hardware_lock); static int rx_buf[RBUF_LEN]; static unsigned int rx_tail, rx_head; -static int debug; +static bool debug; #define dprintk(fmt, args...) \ do { \ if (debug) \ diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 0302d82a12f7..76ea4a8f2c75 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -155,8 +155,8 @@ static struct mutex tx_data_lock; #define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args) /* module parameters */ -static int debug; /* debug output */ -static int tx_only; /* only handle the IR Tx function */ +static bool debug; /* debug output */ +static bool tx_only; /* only handle the IR Tx function */ static int minor = -1; /* minor number */ #define dprintk(fmt, args...) \ diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile index 72816cf16704..337e38c3a0f0 100644 --- a/drivers/staging/media/solo6x10/Makefile +++ b/drivers/staging/media/solo6x10/Makefile @@ -1,3 +1,3 @@ solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o -obj-$(CONFIG_SOLO6X10) := solo6x10.o +obj-$(CONFIG_SOLO6X10) += solo6x10.o diff --git a/drivers/staging/media/solo6x10/jpeg.h b/drivers/staging/media/solo6x10/solo6x10-jpeg.h index 50defec318cc..50defec318cc 100644 --- a/drivers/staging/media/solo6x10/jpeg.h +++ b/drivers/staging/media/solo6x10/solo6x10-jpeg.h diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index bee7280bbed9..f8f0da952288 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -26,7 +26,7 @@ #include <media/videobuf-dma-sg.h> #include "solo6x10.h" #include "tw28.h" -#include "jpeg.h" +#include "solo6x10-jpeg.h" #define MIN_VID_BUFFERS 4 #define FRAME_BUF_SIZE (128 * 1024) diff --git a/drivers/staging/octeon/Makefile b/drivers/staging/octeon/Makefile index fc850bac88c1..9012dee0c348 100644 --- a/drivers/staging/octeon/Makefile +++ b/drivers/staging/octeon/Makefile @@ -20,9 +20,4 @@ octeon-ethernet-y += ethernet-sgmii.o octeon-ethernet-y += ethernet-spi.o octeon-ethernet-y += ethernet-tx.o octeon-ethernet-y += ethernet-xaui.o -octeon-ethernet-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \ - cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \ - cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \ - cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \ - cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o diff --git a/drivers/staging/octeon/cvmx-address.h b/drivers/staging/octeon/cvmx-address.h deleted file mode 100644 index 3c74d826e2e6..000000000000 --- a/drivers/staging/octeon/cvmx-address.h +++ /dev/null @@ -1,274 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2009 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * Typedefs and defines for working with Octeon physical addresses. - * - */ -#ifndef __CVMX_ADDRESS_H__ -#define __CVMX_ADDRESS_H__ - -#if 0 -typedef enum { - CVMX_MIPS_SPACE_XKSEG = 3LL, - CVMX_MIPS_SPACE_XKPHYS = 2LL, - CVMX_MIPS_SPACE_XSSEG = 1LL, - CVMX_MIPS_SPACE_XUSEG = 0LL -} cvmx_mips_space_t; -#endif - -typedef enum { - CVMX_MIPS_XKSEG_SPACE_KSEG0 = 0LL, - CVMX_MIPS_XKSEG_SPACE_KSEG1 = 1LL, - CVMX_MIPS_XKSEG_SPACE_SSEG = 2LL, - CVMX_MIPS_XKSEG_SPACE_KSEG3 = 3LL -} cvmx_mips_xkseg_space_t; - -/* decodes <14:13> of a kseg3 window address */ -typedef enum { - CVMX_ADD_WIN_SCR = 0L, - /* see cvmx_add_win_dma_dec_t for further decode */ - CVMX_ADD_WIN_DMA = 1L, - CVMX_ADD_WIN_UNUSED = 2L, - CVMX_ADD_WIN_UNUSED2 = 3L -} cvmx_add_win_dec_t; - -/* decode within DMA space */ -typedef enum { - /* - * Add store data to the write buffer entry, allocating it if - * necessary. - */ - CVMX_ADD_WIN_DMA_ADD = 0L, - /* send out the write buffer entry to DRAM */ - CVMX_ADD_WIN_DMA_SENDMEM = 1L, - /* store data must be normal DRAM memory space address in this case */ - /* send out the write buffer entry as an IOBDMA command */ - CVMX_ADD_WIN_DMA_SENDDMA = 2L, - /* see CVMX_ADD_WIN_DMA_SEND_DEC for data contents */ - /* send out the write buffer entry as an IO write */ - CVMX_ADD_WIN_DMA_SENDIO = 3L, - /* store data must be normal IO space address in this case */ - /* send out a single-tick command on the NCB bus */ - CVMX_ADD_WIN_DMA_SENDSINGLE = 4L, - /* no write buffer data needed/used */ -} cvmx_add_win_dma_dec_t; - -/* - * Physical Address Decode - * - * Octeon-I HW never interprets this X (<39:36> reserved - * for future expansion), software should set to 0. - * - * - 0x0 XXX0 0000 0000 to DRAM Cached - * - 0x0 XXX0 0FFF FFFF - * - * - 0x0 XXX0 1000 0000 to Boot Bus Uncached (Converted to 0x1 00X0 1000 0000 - * - 0x0 XXX0 1FFF FFFF + EJTAG to 0x1 00X0 1FFF FFFF) - * - * - 0x0 XXX0 2000 0000 to DRAM Cached - * - 0x0 XXXF FFFF FFFF - * - * - 0x1 00X0 0000 0000 to Boot Bus Uncached - * - 0x1 00XF FFFF FFFF - * - * - 0x1 01X0 0000 0000 to Other NCB Uncached - * - 0x1 FFXF FFFF FFFF devices - * - * Decode of all Octeon addresses - */ -typedef union { - - uint64_t u64; - /* mapped or unmapped virtual address */ - struct { - uint64_t R:2; - uint64_t offset:62; - } sva; - - /* mapped USEG virtual addresses (typically) */ - struct { - uint64_t zeroes:33; - uint64_t offset:31; - } suseg; - - /* mapped or unmapped virtual address */ - struct { - uint64_t ones:33; - uint64_t sp:2; - uint64_t offset:29; - } sxkseg; - - /* - * physical address accessed through xkphys unmapped virtual - * address. - */ - struct { - uint64_t R:2; /* CVMX_MIPS_SPACE_XKPHYS in this case */ - uint64_t cca:3; /* ignored by octeon */ - uint64_t mbz:10; - uint64_t pa:49; /* physical address */ - } sxkphys; - - /* physical address */ - struct { - uint64_t mbz:15; - /* if set, the address is uncached and resides on MCB bus */ - uint64_t is_io:1; - /* - * the hardware ignores this field when is_io==0, else - * device ID. - */ - uint64_t did:8; - /* the hardware ignores <39:36> in Octeon I */ - uint64_t unaddr:4; - uint64_t offset:36; - } sphys; - - /* physical mem address */ - struct { - /* techically, <47:40> are dont-cares */ - uint64_t zeroes:24; - /* the hardware ignores <39:36> in Octeon I */ - uint64_t unaddr:4; - uint64_t offset:36; - } smem; - - /* physical IO address */ - struct { - uint64_t mem_region:2; - uint64_t mbz:13; - /* 1 in this case */ - uint64_t is_io:1; - /* - * The hardware ignores this field when is_io==0, else - * device ID. - */ - uint64_t did:8; - /* the hardware ignores <39:36> in Octeon I */ - uint64_t unaddr:4; - uint64_t offset:36; - } sio; - - /* - * Scratchpad virtual address - accessed through a window at - * the end of kseg3 - */ - struct { - uint64_t ones:49; - /* CVMX_ADD_WIN_SCR (0) in this case */ - cvmx_add_win_dec_t csrdec:2; - uint64_t addr:13; - } sscr; - - /* there should only be stores to IOBDMA space, no loads */ - /* - * IOBDMA virtual address - accessed through a window at the - * end of kseg3 - */ - struct { - uint64_t ones:49; - uint64_t csrdec:2; /* CVMX_ADD_WIN_DMA (1) in this case */ - uint64_t unused2:3; - uint64_t type:3; - uint64_t addr:7; - } sdma; - - struct { - uint64_t didspace:24; - uint64_t unused:40; - } sfilldidspace; - -} cvmx_addr_t; - -/* These macros for used by 32 bit applications */ - -#define CVMX_MIPS32_SPACE_KSEG0 1l -#define CVMX_ADD_SEG32(segment, add) \ - (((int32_t)segment << 31) | (int32_t)(add)) - -/* - * Currently all IOs are performed using XKPHYS addressing. Linux uses - * the CvmMemCtl register to enable XKPHYS addressing to IO space from - * user mode. Future OSes may need to change the upper bits of IO - * addresses. The following define controls the upper two bits for all - * IO addresses generated by the simple executive library. - */ -#define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS - -/* These macros simplify the process of creating common IO addresses */ -#define CVMX_ADD_SEG(segment, add) ((((uint64_t)segment) << 62) | (add)) -#ifndef CVMX_ADD_IO_SEG -#define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) -#endif -#define CVMX_ADDR_DIDSPACE(did) (((CVMX_IO_SEG) << 22) | ((1ULL) << 8) | (did)) -#define CVMX_ADDR_DID(did) (CVMX_ADDR_DIDSPACE(did) << 40) -#define CVMX_FULL_DID(did, subdid) (((did) << 3) | (subdid)) - - /* from include/ncb_rsl_id.v */ -#define CVMX_OCT_DID_MIS 0ULL /* misc stuff */ -#define CVMX_OCT_DID_GMX0 1ULL -#define CVMX_OCT_DID_GMX1 2ULL -#define CVMX_OCT_DID_PCI 3ULL -#define CVMX_OCT_DID_KEY 4ULL -#define CVMX_OCT_DID_FPA 5ULL -#define CVMX_OCT_DID_DFA 6ULL -#define CVMX_OCT_DID_ZIP 7ULL -#define CVMX_OCT_DID_RNG 8ULL -#define CVMX_OCT_DID_IPD 9ULL -#define CVMX_OCT_DID_PKT 10ULL -#define CVMX_OCT_DID_TIM 11ULL -#define CVMX_OCT_DID_TAG 12ULL - /* the rest are not on the IO bus */ -#define CVMX_OCT_DID_L2C 16ULL -#define CVMX_OCT_DID_LMC 17ULL -#define CVMX_OCT_DID_SPX0 18ULL -#define CVMX_OCT_DID_SPX1 19ULL -#define CVMX_OCT_DID_PIP 20ULL -#define CVMX_OCT_DID_ASX0 22ULL -#define CVMX_OCT_DID_ASX1 23ULL -#define CVMX_OCT_DID_IOB 30ULL - -#define CVMX_OCT_DID_PKT_SEND CVMX_FULL_DID(CVMX_OCT_DID_PKT, 2ULL) -#define CVMX_OCT_DID_TAG_SWTAG CVMX_FULL_DID(CVMX_OCT_DID_TAG, 0ULL) -#define CVMX_OCT_DID_TAG_TAG1 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 1ULL) -#define CVMX_OCT_DID_TAG_TAG2 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 2ULL) -#define CVMX_OCT_DID_TAG_TAG3 CVMX_FULL_DID(CVMX_OCT_DID_TAG, 3ULL) -#define CVMX_OCT_DID_TAG_NULL_RD CVMX_FULL_DID(CVMX_OCT_DID_TAG, 4ULL) -#define CVMX_OCT_DID_TAG_CSR CVMX_FULL_DID(CVMX_OCT_DID_TAG, 7ULL) -#define CVMX_OCT_DID_FAU_FAI CVMX_FULL_DID(CVMX_OCT_DID_IOB, 0ULL) -#define CVMX_OCT_DID_TIM_CSR CVMX_FULL_DID(CVMX_OCT_DID_TIM, 0ULL) -#define CVMX_OCT_DID_KEY_RW CVMX_FULL_DID(CVMX_OCT_DID_KEY, 0ULL) -#define CVMX_OCT_DID_PCI_6 CVMX_FULL_DID(CVMX_OCT_DID_PCI, 6ULL) -#define CVMX_OCT_DID_MIS_BOO CVMX_FULL_DID(CVMX_OCT_DID_MIS, 0ULL) -#define CVMX_OCT_DID_PCI_RML CVMX_FULL_DID(CVMX_OCT_DID_PCI, 0ULL) -#define CVMX_OCT_DID_IPD_CSR CVMX_FULL_DID(CVMX_OCT_DID_IPD, 7ULL) -#define CVMX_OCT_DID_DFA_CSR CVMX_FULL_DID(CVMX_OCT_DID_DFA, 7ULL) -#define CVMX_OCT_DID_MIS_CSR CVMX_FULL_DID(CVMX_OCT_DID_MIS, 7ULL) -#define CVMX_OCT_DID_ZIP_CSR CVMX_FULL_DID(CVMX_OCT_DID_ZIP, 0ULL) - -#endif /* __CVMX_ADDRESS_H__ */ diff --git a/drivers/staging/octeon/cvmx-asxx-defs.h b/drivers/staging/octeon/cvmx-asxx-defs.h deleted file mode 100644 index 91415a85e8d2..000000000000 --- a/drivers/staging/octeon/cvmx-asxx-defs.h +++ /dev/null @@ -1,475 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_ASXX_DEFS_H__ -#define __CVMX_ASXX_DEFS_H__ - -#define CVMX_ASXX_GMII_RX_CLK_SET(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000180ull + (((block_id) & 0) * 0x8000000ull)) -#define CVMX_ASXX_GMII_RX_DAT_SET(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000188ull + (((block_id) & 0) * 0x8000000ull)) -#define CVMX_ASXX_INT_EN(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000018ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_INT_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000010ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_MII_RX_DAT_SET(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000190ull + (((block_id) & 0) * 0x8000000ull)) -#define CVMX_ASXX_PRT_LOOP(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000040ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_BYPASS(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000248ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_BYPASS_SETTING(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000250ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_COMP(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000220ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_DATA_DRV(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000218ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_FCRAM_MODE(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000210ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_NCTL_STRONG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000230ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_NCTL_WEAK(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000240ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_PCTL_STRONG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000228ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_PCTL_WEAK(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000238ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RLD_SETTING(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000258ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RX_CLK_SETX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000020ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RX_PRT_EN(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000000ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RX_WOL(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000100ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RX_WOL_MSK(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000108ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RX_WOL_POWOK(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000118ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_RX_WOL_SIG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000110ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_TX_CLK_SETX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000048ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_TX_COMP_BYP(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000068ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_TX_HI_WATERX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000080ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_ASXX_TX_PRT_EN(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000008ull + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_asxx_gmii_rx_clk_set { - uint64_t u64; - struct cvmx_asxx_gmii_rx_clk_set_s { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } s; - struct cvmx_asxx_gmii_rx_clk_set_s cn30xx; - struct cvmx_asxx_gmii_rx_clk_set_s cn31xx; - struct cvmx_asxx_gmii_rx_clk_set_s cn50xx; -}; - -union cvmx_asxx_gmii_rx_dat_set { - uint64_t u64; - struct cvmx_asxx_gmii_rx_dat_set_s { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } s; - struct cvmx_asxx_gmii_rx_dat_set_s cn30xx; - struct cvmx_asxx_gmii_rx_dat_set_s cn31xx; - struct cvmx_asxx_gmii_rx_dat_set_s cn50xx; -}; - -union cvmx_asxx_int_en { - uint64_t u64; - struct cvmx_asxx_int_en_s { - uint64_t reserved_12_63:52; - uint64_t txpsh:4; - uint64_t txpop:4; - uint64_t ovrflw:4; - } s; - struct cvmx_asxx_int_en_cn30xx { - uint64_t reserved_11_63:53; - uint64_t txpsh:3; - uint64_t reserved_7_7:1; - uint64_t txpop:3; - uint64_t reserved_3_3:1; - uint64_t ovrflw:3; - } cn30xx; - struct cvmx_asxx_int_en_cn30xx cn31xx; - struct cvmx_asxx_int_en_s cn38xx; - struct cvmx_asxx_int_en_s cn38xxp2; - struct cvmx_asxx_int_en_cn30xx cn50xx; - struct cvmx_asxx_int_en_s cn58xx; - struct cvmx_asxx_int_en_s cn58xxp1; -}; - -union cvmx_asxx_int_reg { - uint64_t u64; - struct cvmx_asxx_int_reg_s { - uint64_t reserved_12_63:52; - uint64_t txpsh:4; - uint64_t txpop:4; - uint64_t ovrflw:4; - } s; - struct cvmx_asxx_int_reg_cn30xx { - uint64_t reserved_11_63:53; - uint64_t txpsh:3; - uint64_t reserved_7_7:1; - uint64_t txpop:3; - uint64_t reserved_3_3:1; - uint64_t ovrflw:3; - } cn30xx; - struct cvmx_asxx_int_reg_cn30xx cn31xx; - struct cvmx_asxx_int_reg_s cn38xx; - struct cvmx_asxx_int_reg_s cn38xxp2; - struct cvmx_asxx_int_reg_cn30xx cn50xx; - struct cvmx_asxx_int_reg_s cn58xx; - struct cvmx_asxx_int_reg_s cn58xxp1; -}; - -union cvmx_asxx_mii_rx_dat_set { - uint64_t u64; - struct cvmx_asxx_mii_rx_dat_set_s { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } s; - struct cvmx_asxx_mii_rx_dat_set_s cn30xx; - struct cvmx_asxx_mii_rx_dat_set_s cn50xx; -}; - -union cvmx_asxx_prt_loop { - uint64_t u64; - struct cvmx_asxx_prt_loop_s { - uint64_t reserved_8_63:56; - uint64_t ext_loop:4; - uint64_t int_loop:4; - } s; - struct cvmx_asxx_prt_loop_cn30xx { - uint64_t reserved_7_63:57; - uint64_t ext_loop:3; - uint64_t reserved_3_3:1; - uint64_t int_loop:3; - } cn30xx; - struct cvmx_asxx_prt_loop_cn30xx cn31xx; - struct cvmx_asxx_prt_loop_s cn38xx; - struct cvmx_asxx_prt_loop_s cn38xxp2; - struct cvmx_asxx_prt_loop_cn30xx cn50xx; - struct cvmx_asxx_prt_loop_s cn58xx; - struct cvmx_asxx_prt_loop_s cn58xxp1; -}; - -union cvmx_asxx_rld_bypass { - uint64_t u64; - struct cvmx_asxx_rld_bypass_s { - uint64_t reserved_1_63:63; - uint64_t bypass:1; - } s; - struct cvmx_asxx_rld_bypass_s cn38xx; - struct cvmx_asxx_rld_bypass_s cn38xxp2; - struct cvmx_asxx_rld_bypass_s cn58xx; - struct cvmx_asxx_rld_bypass_s cn58xxp1; -}; - -union cvmx_asxx_rld_bypass_setting { - uint64_t u64; - struct cvmx_asxx_rld_bypass_setting_s { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } s; - struct cvmx_asxx_rld_bypass_setting_s cn38xx; - struct cvmx_asxx_rld_bypass_setting_s cn38xxp2; - struct cvmx_asxx_rld_bypass_setting_s cn58xx; - struct cvmx_asxx_rld_bypass_setting_s cn58xxp1; -}; - -union cvmx_asxx_rld_comp { - uint64_t u64; - struct cvmx_asxx_rld_comp_s { - uint64_t reserved_9_63:55; - uint64_t pctl:5; - uint64_t nctl:4; - } s; - struct cvmx_asxx_rld_comp_cn38xx { - uint64_t reserved_8_63:56; - uint64_t pctl:4; - uint64_t nctl:4; - } cn38xx; - struct cvmx_asxx_rld_comp_cn38xx cn38xxp2; - struct cvmx_asxx_rld_comp_s cn58xx; - struct cvmx_asxx_rld_comp_s cn58xxp1; -}; - -union cvmx_asxx_rld_data_drv { - uint64_t u64; - struct cvmx_asxx_rld_data_drv_s { - uint64_t reserved_8_63:56; - uint64_t pctl:4; - uint64_t nctl:4; - } s; - struct cvmx_asxx_rld_data_drv_s cn38xx; - struct cvmx_asxx_rld_data_drv_s cn38xxp2; - struct cvmx_asxx_rld_data_drv_s cn58xx; - struct cvmx_asxx_rld_data_drv_s cn58xxp1; -}; - -union cvmx_asxx_rld_fcram_mode { - uint64_t u64; - struct cvmx_asxx_rld_fcram_mode_s { - uint64_t reserved_1_63:63; - uint64_t mode:1; - } s; - struct cvmx_asxx_rld_fcram_mode_s cn38xx; - struct cvmx_asxx_rld_fcram_mode_s cn38xxp2; -}; - -union cvmx_asxx_rld_nctl_strong { - uint64_t u64; - struct cvmx_asxx_rld_nctl_strong_s { - uint64_t reserved_5_63:59; - uint64_t nctl:5; - } s; - struct cvmx_asxx_rld_nctl_strong_s cn38xx; - struct cvmx_asxx_rld_nctl_strong_s cn38xxp2; - struct cvmx_asxx_rld_nctl_strong_s cn58xx; - struct cvmx_asxx_rld_nctl_strong_s cn58xxp1; -}; - -union cvmx_asxx_rld_nctl_weak { - uint64_t u64; - struct cvmx_asxx_rld_nctl_weak_s { - uint64_t reserved_5_63:59; - uint64_t nctl:5; - } s; - struct cvmx_asxx_rld_nctl_weak_s cn38xx; - struct cvmx_asxx_rld_nctl_weak_s cn38xxp2; - struct cvmx_asxx_rld_nctl_weak_s cn58xx; - struct cvmx_asxx_rld_nctl_weak_s cn58xxp1; -}; - -union cvmx_asxx_rld_pctl_strong { - uint64_t u64; - struct cvmx_asxx_rld_pctl_strong_s { - uint64_t reserved_5_63:59; - uint64_t pctl:5; - } s; - struct cvmx_asxx_rld_pctl_strong_s cn38xx; - struct cvmx_asxx_rld_pctl_strong_s cn38xxp2; - struct cvmx_asxx_rld_pctl_strong_s cn58xx; - struct cvmx_asxx_rld_pctl_strong_s cn58xxp1; -}; - -union cvmx_asxx_rld_pctl_weak { - uint64_t u64; - struct cvmx_asxx_rld_pctl_weak_s { - uint64_t reserved_5_63:59; - uint64_t pctl:5; - } s; - struct cvmx_asxx_rld_pctl_weak_s cn38xx; - struct cvmx_asxx_rld_pctl_weak_s cn38xxp2; - struct cvmx_asxx_rld_pctl_weak_s cn58xx; - struct cvmx_asxx_rld_pctl_weak_s cn58xxp1; -}; - -union cvmx_asxx_rld_setting { - uint64_t u64; - struct cvmx_asxx_rld_setting_s { - uint64_t reserved_13_63:51; - uint64_t dfaset:5; - uint64_t dfalag:1; - uint64_t dfalead:1; - uint64_t dfalock:1; - uint64_t setting:5; - } s; - struct cvmx_asxx_rld_setting_cn38xx { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } cn38xx; - struct cvmx_asxx_rld_setting_cn38xx cn38xxp2; - struct cvmx_asxx_rld_setting_s cn58xx; - struct cvmx_asxx_rld_setting_s cn58xxp1; -}; - -union cvmx_asxx_rx_clk_setx { - uint64_t u64; - struct cvmx_asxx_rx_clk_setx_s { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } s; - struct cvmx_asxx_rx_clk_setx_s cn30xx; - struct cvmx_asxx_rx_clk_setx_s cn31xx; - struct cvmx_asxx_rx_clk_setx_s cn38xx; - struct cvmx_asxx_rx_clk_setx_s cn38xxp2; - struct cvmx_asxx_rx_clk_setx_s cn50xx; - struct cvmx_asxx_rx_clk_setx_s cn58xx; - struct cvmx_asxx_rx_clk_setx_s cn58xxp1; -}; - -union cvmx_asxx_rx_prt_en { - uint64_t u64; - struct cvmx_asxx_rx_prt_en_s { - uint64_t reserved_4_63:60; - uint64_t prt_en:4; - } s; - struct cvmx_asxx_rx_prt_en_cn30xx { - uint64_t reserved_3_63:61; - uint64_t prt_en:3; - } cn30xx; - struct cvmx_asxx_rx_prt_en_cn30xx cn31xx; - struct cvmx_asxx_rx_prt_en_s cn38xx; - struct cvmx_asxx_rx_prt_en_s cn38xxp2; - struct cvmx_asxx_rx_prt_en_cn30xx cn50xx; - struct cvmx_asxx_rx_prt_en_s cn58xx; - struct cvmx_asxx_rx_prt_en_s cn58xxp1; -}; - -union cvmx_asxx_rx_wol { - uint64_t u64; - struct cvmx_asxx_rx_wol_s { - uint64_t reserved_2_63:62; - uint64_t status:1; - uint64_t enable:1; - } s; - struct cvmx_asxx_rx_wol_s cn38xx; - struct cvmx_asxx_rx_wol_s cn38xxp2; -}; - -union cvmx_asxx_rx_wol_msk { - uint64_t u64; - struct cvmx_asxx_rx_wol_msk_s { - uint64_t msk:64; - } s; - struct cvmx_asxx_rx_wol_msk_s cn38xx; - struct cvmx_asxx_rx_wol_msk_s cn38xxp2; -}; - -union cvmx_asxx_rx_wol_powok { - uint64_t u64; - struct cvmx_asxx_rx_wol_powok_s { - uint64_t reserved_1_63:63; - uint64_t powerok:1; - } s; - struct cvmx_asxx_rx_wol_powok_s cn38xx; - struct cvmx_asxx_rx_wol_powok_s cn38xxp2; -}; - -union cvmx_asxx_rx_wol_sig { - uint64_t u64; - struct cvmx_asxx_rx_wol_sig_s { - uint64_t reserved_32_63:32; - uint64_t sig:32; - } s; - struct cvmx_asxx_rx_wol_sig_s cn38xx; - struct cvmx_asxx_rx_wol_sig_s cn38xxp2; -}; - -union cvmx_asxx_tx_clk_setx { - uint64_t u64; - struct cvmx_asxx_tx_clk_setx_s { - uint64_t reserved_5_63:59; - uint64_t setting:5; - } s; - struct cvmx_asxx_tx_clk_setx_s cn30xx; - struct cvmx_asxx_tx_clk_setx_s cn31xx; - struct cvmx_asxx_tx_clk_setx_s cn38xx; - struct cvmx_asxx_tx_clk_setx_s cn38xxp2; - struct cvmx_asxx_tx_clk_setx_s cn50xx; - struct cvmx_asxx_tx_clk_setx_s cn58xx; - struct cvmx_asxx_tx_clk_setx_s cn58xxp1; -}; - -union cvmx_asxx_tx_comp_byp { - uint64_t u64; - struct cvmx_asxx_tx_comp_byp_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_asxx_tx_comp_byp_cn30xx { - uint64_t reserved_9_63:55; - uint64_t bypass:1; - uint64_t pctl:4; - uint64_t nctl:4; - } cn30xx; - struct cvmx_asxx_tx_comp_byp_cn30xx cn31xx; - struct cvmx_asxx_tx_comp_byp_cn38xx { - uint64_t reserved_8_63:56; - uint64_t pctl:4; - uint64_t nctl:4; - } cn38xx; - struct cvmx_asxx_tx_comp_byp_cn38xx cn38xxp2; - struct cvmx_asxx_tx_comp_byp_cn50xx { - uint64_t reserved_17_63:47; - uint64_t bypass:1; - uint64_t reserved_13_15:3; - uint64_t pctl:5; - uint64_t reserved_5_7:3; - uint64_t nctl:5; - } cn50xx; - struct cvmx_asxx_tx_comp_byp_cn58xx { - uint64_t reserved_13_63:51; - uint64_t pctl:5; - uint64_t reserved_5_7:3; - uint64_t nctl:5; - } cn58xx; - struct cvmx_asxx_tx_comp_byp_cn58xx cn58xxp1; -}; - -union cvmx_asxx_tx_hi_waterx { - uint64_t u64; - struct cvmx_asxx_tx_hi_waterx_s { - uint64_t reserved_4_63:60; - uint64_t mark:4; - } s; - struct cvmx_asxx_tx_hi_waterx_cn30xx { - uint64_t reserved_3_63:61; - uint64_t mark:3; - } cn30xx; - struct cvmx_asxx_tx_hi_waterx_cn30xx cn31xx; - struct cvmx_asxx_tx_hi_waterx_s cn38xx; - struct cvmx_asxx_tx_hi_waterx_s cn38xxp2; - struct cvmx_asxx_tx_hi_waterx_cn30xx cn50xx; - struct cvmx_asxx_tx_hi_waterx_s cn58xx; - struct cvmx_asxx_tx_hi_waterx_s cn58xxp1; -}; - -union cvmx_asxx_tx_prt_en { - uint64_t u64; - struct cvmx_asxx_tx_prt_en_s { - uint64_t reserved_4_63:60; - uint64_t prt_en:4; - } s; - struct cvmx_asxx_tx_prt_en_cn30xx { - uint64_t reserved_3_63:61; - uint64_t prt_en:3; - } cn30xx; - struct cvmx_asxx_tx_prt_en_cn30xx cn31xx; - struct cvmx_asxx_tx_prt_en_s cn38xx; - struct cvmx_asxx_tx_prt_en_s cn38xxp2; - struct cvmx_asxx_tx_prt_en_cn30xx cn50xx; - struct cvmx_asxx_tx_prt_en_s cn58xx; - struct cvmx_asxx_tx_prt_en_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-cmd-queue.c b/drivers/staging/octeon/cvmx-cmd-queue.c deleted file mode 100644 index e9809d375162..000000000000 --- a/drivers/staging/octeon/cvmx-cmd-queue.c +++ /dev/null @@ -1,306 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Support functions for managing command queues used for - * various hardware blocks. - */ - -#include <linux/kernel.h> - -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" -#include "cvmx-fpa.h" -#include "cvmx-cmd-queue.h" - -#include <asm/octeon/cvmx-npei-defs.h> -#include <asm/octeon/cvmx-pexp-defs.h> -#include "cvmx-pko-defs.h" - -/** - * This application uses this pointer to access the global queue - * state. It points to a bootmem named block. - */ -__cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr; - -/** - * Initialize the Global queue state pointer. - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void) -{ - char *alloc_name = "cvmx_cmd_queues"; -#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32 - extern uint64_t octeon_reserve32_memory; -#endif - - if (likely(__cvmx_cmd_queue_state_ptr)) - return CVMX_CMD_QUEUE_SUCCESS; - -#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32 - if (octeon_reserve32_memory) - __cvmx_cmd_queue_state_ptr = - cvmx_bootmem_alloc_named_range(sizeof(*__cvmx_cmd_queue_state_ptr), - octeon_reserve32_memory, - octeon_reserve32_memory + - (CONFIG_CAVIUM_RESERVE32 << - 20) - 1, 128, alloc_name); - else -#endif - __cvmx_cmd_queue_state_ptr = - cvmx_bootmem_alloc_named(sizeof(*__cvmx_cmd_queue_state_ptr), - 128, - alloc_name); - if (__cvmx_cmd_queue_state_ptr) - memset(__cvmx_cmd_queue_state_ptr, 0, - sizeof(*__cvmx_cmd_queue_state_ptr)); - else { - struct cvmx_bootmem_named_block_desc *block_desc = - cvmx_bootmem_find_named_block(alloc_name); - if (block_desc) - __cvmx_cmd_queue_state_ptr = - cvmx_phys_to_ptr(block_desc->base_addr); - else { - cvmx_dprintf - ("ERROR: cvmx_cmd_queue_initialize: Unable to get named block %s.\n", - alloc_name); - return CVMX_CMD_QUEUE_NO_MEMORY; - } - } - return CVMX_CMD_QUEUE_SUCCESS; -} - -/** - * Initialize a command queue for use. The initial FPA buffer is - * allocated and the hardware unit is configured to point to the - * new command queue. - * - * @queue_id: Hardware command queue to initialize. - * @max_depth: Maximum outstanding commands that can be queued. - * @fpa_pool: FPA pool the command queues should come from. - * @pool_size: Size of each buffer in the FPA pool (bytes) - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, - int max_depth, int fpa_pool, - int pool_size) -{ - __cvmx_cmd_queue_state_t *qstate; - cvmx_cmd_queue_result_t result = __cvmx_cmd_queue_init_state_ptr(); - if (result != CVMX_CMD_QUEUE_SUCCESS) - return result; - - qstate = __cvmx_cmd_queue_get_state(queue_id); - if (qstate == NULL) - return CVMX_CMD_QUEUE_INVALID_PARAM; - - /* - * We artificially limit max_depth to 1<<20 words. It is an - * arbitrary limit. - */ - if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH) { - if ((max_depth < 0) || (max_depth > 1 << 20)) - return CVMX_CMD_QUEUE_INVALID_PARAM; - } else if (max_depth != 0) - return CVMX_CMD_QUEUE_INVALID_PARAM; - - if ((fpa_pool < 0) || (fpa_pool > 7)) - return CVMX_CMD_QUEUE_INVALID_PARAM; - if ((pool_size < 128) || (pool_size > 65536)) - return CVMX_CMD_QUEUE_INVALID_PARAM; - - /* See if someone else has already initialized the queue */ - if (qstate->base_ptr_div128) { - if (max_depth != (int)qstate->max_depth) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " - "Queue already initialized with different " - "max_depth (%d).\n", - (int)qstate->max_depth); - return CVMX_CMD_QUEUE_INVALID_PARAM; - } - if (fpa_pool != qstate->fpa_pool) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " - "Queue already initialized with different " - "FPA pool (%u).\n", - qstate->fpa_pool); - return CVMX_CMD_QUEUE_INVALID_PARAM; - } - if ((pool_size >> 3) - 1 != qstate->pool_size_m1) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " - "Queue already initialized with different " - "FPA pool size (%u).\n", - (qstate->pool_size_m1 + 1) << 3); - return CVMX_CMD_QUEUE_INVALID_PARAM; - } - CVMX_SYNCWS; - return CVMX_CMD_QUEUE_ALREADY_SETUP; - } else { - union cvmx_fpa_ctl_status status; - void *buffer; - - status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS); - if (!status.s.enb) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " - "FPA is not enabled.\n"); - return CVMX_CMD_QUEUE_NO_MEMORY; - } - buffer = cvmx_fpa_alloc(fpa_pool); - if (buffer == NULL) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: " - "Unable to allocate initial buffer.\n"); - return CVMX_CMD_QUEUE_NO_MEMORY; - } - - memset(qstate, 0, sizeof(*qstate)); - qstate->max_depth = max_depth; - qstate->fpa_pool = fpa_pool; - qstate->pool_size_m1 = (pool_size >> 3) - 1; - qstate->base_ptr_div128 = cvmx_ptr_to_phys(buffer) / 128; - /* - * We zeroed the now serving field so we need to also - * zero the ticket. - */ - __cvmx_cmd_queue_state_ptr-> - ticket[__cvmx_cmd_queue_get_index(queue_id)] = 0; - CVMX_SYNCWS; - return CVMX_CMD_QUEUE_SUCCESS; - } -} - -/** - * Shutdown a queue a free it's command buffers to the FPA. The - * hardware connected to the queue must be stopped before this - * function is called. - * - * @queue_id: Queue to shutdown - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id) -{ - __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); - if (qptr == NULL) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Unable to " - "get queue information.\n"); - return CVMX_CMD_QUEUE_INVALID_PARAM; - } - - if (cvmx_cmd_queue_length(queue_id) > 0) { - cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Queue still " - "has data in it.\n"); - return CVMX_CMD_QUEUE_FULL; - } - - __cvmx_cmd_queue_lock(queue_id, qptr); - if (qptr->base_ptr_div128) { - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) qptr->base_ptr_div128 << 7), - qptr->fpa_pool, 0); - qptr->base_ptr_div128 = 0; - } - __cvmx_cmd_queue_unlock(qptr); - - return CVMX_CMD_QUEUE_SUCCESS; -} - -/** - * Return the number of command words pending in the queue. This - * function may be relatively slow for some hardware units. - * - * @queue_id: Hardware command queue to query - * - * Returns Number of outstanding commands - */ -int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id) -{ - if (CVMX_ENABLE_PARAMETER_CHECKING) { - if (__cvmx_cmd_queue_get_state(queue_id) == NULL) - return CVMX_CMD_QUEUE_INVALID_PARAM; - } - - /* - * The cast is here so gcc with check that all values in the - * cvmx_cmd_queue_id_t enumeration are here. - */ - switch ((cvmx_cmd_queue_id_t) (queue_id & 0xff0000)) { - case CVMX_CMD_QUEUE_PKO_BASE: - /* - * FIXME: Need atomic lock on - * CVMX_PKO_REG_READ_IDX. Right now we are normally - * called with the queue lock, so that is a SLIGHT - * amount of protection. - */ - cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue_id & 0xffff); - if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { - union cvmx_pko_mem_debug9 debug9; - debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9); - return debug9.cn38xx.doorbell; - } else { - union cvmx_pko_mem_debug8 debug8; - debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8); - return debug8.cn58xx.doorbell; - } - case CVMX_CMD_QUEUE_ZIP: - case CVMX_CMD_QUEUE_DFA: - case CVMX_CMD_QUEUE_RAID: - /* FIXME: Implement other lengths */ - return 0; - case CVMX_CMD_QUEUE_DMA_BASE: - { - union cvmx_npei_dmax_counts dmax_counts; - dmax_counts.u64 = - cvmx_read_csr(CVMX_PEXP_NPEI_DMAX_COUNTS - (queue_id & 0x7)); - return dmax_counts.s.dbell; - } - case CVMX_CMD_QUEUE_END: - return CVMX_CMD_QUEUE_INVALID_PARAM; - } - return CVMX_CMD_QUEUE_INVALID_PARAM; -} - -/** - * Return the command buffer to be written to. The purpose of this - * function is to allow CVMX routine access t othe low level buffer - * for initial hardware setup. User applications should not call this - * function directly. - * - * @queue_id: Command queue to query - * - * Returns Command buffer or NULL on failure - */ -void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id) -{ - __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); - if (qptr && qptr->base_ptr_div128) - return cvmx_phys_to_ptr((uint64_t) qptr->base_ptr_div128 << 7); - else - return NULL; -} diff --git a/drivers/staging/octeon/cvmx-cmd-queue.h b/drivers/staging/octeon/cvmx-cmd-queue.h deleted file mode 100644 index 614653b686a0..000000000000 --- a/drivers/staging/octeon/cvmx-cmd-queue.h +++ /dev/null @@ -1,617 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Support functions for managing command queues used for - * various hardware blocks. - * - * The common command queue infrastructure abstracts out the - * software necessary for adding to Octeon's chained queue - * structures. These structures are used for commands to the - * PKO, ZIP, DFA, RAID, and DMA engine blocks. Although each - * hardware unit takes commands and CSRs of different types, - * they all use basic linked command buffers to store the - * pending request. In general, users of the CVMX API don't - * call cvmx-cmd-queue functions directly. Instead the hardware - * unit specific wrapper should be used. The wrappers perform - * unit specific validation and CSR writes to submit the - * commands. - * - * Even though most software will never directly interact with - * cvmx-cmd-queue, knowledge of its internal working can help - * in diagnosing performance problems and help with debugging. - * - * Command queue pointers are stored in a global named block - * called "cvmx_cmd_queues". Except for the PKO queues, each - * hardware queue is stored in its own cache line to reduce SMP - * contention on spin locks. The PKO queues are stored such that - * every 16th queue is next to each other in memory. This scheme - * allows for queues being in separate cache lines when there - * are low number of queues per port. With 16 queues per port, - * the first queue for each port is in the same cache area. The - * second queues for each port are in another area, etc. This - * allows software to implement very efficient lockless PKO with - * 16 queues per port using a minimum of cache lines per core. - * All queues for a given core will be isolated in the same - * cache area. - * - * In addition to the memory pointer layout, cvmx-cmd-queue - * provides an optimized fair ll/sc locking mechanism for the - * queues. The lock uses a "ticket / now serving" model to - * maintain fair order on contended locks. In addition, it uses - * predicted locking time to limit cache contention. When a core - * know it must wait in line for a lock, it spins on the - * internal cycle counter to completely eliminate any causes of - * bus traffic. - * - */ - -#ifndef __CVMX_CMD_QUEUE_H__ -#define __CVMX_CMD_QUEUE_H__ - -#include <linux/prefetch.h> - -#include "cvmx-fpa.h" -/** - * By default we disable the max depth support. Most programs - * don't use it and it slows down the command queue processing - * significantly. - */ -#ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH -#define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0 -#endif - -/** - * Enumeration representing all hardware blocks that use command - * queues. Each hardware block has up to 65536 sub identifiers for - * multiple command queues. Not all chips support all hardware - * units. - */ -typedef enum { - CVMX_CMD_QUEUE_PKO_BASE = 0x00000, - -#define CVMX_CMD_QUEUE_PKO(queue) \ - ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_PKO_BASE + (0xffff&(queue)))) - - CVMX_CMD_QUEUE_ZIP = 0x10000, - CVMX_CMD_QUEUE_DFA = 0x20000, - CVMX_CMD_QUEUE_RAID = 0x30000, - CVMX_CMD_QUEUE_DMA_BASE = 0x40000, - -#define CVMX_CMD_QUEUE_DMA(queue) \ - ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_DMA_BASE + (0xffff&(queue)))) - - CVMX_CMD_QUEUE_END = 0x50000, -} cvmx_cmd_queue_id_t; - -/** - * Command write operations can fail if the command queue needs - * a new buffer and the associated FPA pool is empty. It can also - * fail if the number of queued command words reaches the maximum - * set at initialization. - */ -typedef enum { - CVMX_CMD_QUEUE_SUCCESS = 0, - CVMX_CMD_QUEUE_NO_MEMORY = -1, - CVMX_CMD_QUEUE_FULL = -2, - CVMX_CMD_QUEUE_INVALID_PARAM = -3, - CVMX_CMD_QUEUE_ALREADY_SETUP = -4, -} cvmx_cmd_queue_result_t; - -typedef struct { - /* You have lock when this is your ticket */ - uint8_t now_serving; - uint64_t unused1:24; - /* Maximum outstanding command words */ - uint32_t max_depth; - /* FPA pool buffers come from */ - uint64_t fpa_pool:3; - /* Top of command buffer pointer shifted 7 */ - uint64_t base_ptr_div128:29; - uint64_t unused2:6; - /* FPA buffer size in 64bit words minus 1 */ - uint64_t pool_size_m1:13; - /* Number of commands already used in buffer */ - uint64_t index:13; -} __cvmx_cmd_queue_state_t; - -/** - * This structure contains the global state of all command queues. - * It is stored in a bootmem named block and shared by all - * applications running on Octeon. Tickets are stored in a differnet - * cahce line that queue information to reduce the contention on the - * ll/sc used to get a ticket. If this is not the case, the update - * of queue state causes the ll/sc to fail quite often. - */ -typedef struct { - uint64_t ticket[(CVMX_CMD_QUEUE_END >> 16) * 256]; - __cvmx_cmd_queue_state_t state[(CVMX_CMD_QUEUE_END >> 16) * 256]; -} __cvmx_cmd_queue_all_state_t; - -/** - * Initialize a command queue for use. The initial FPA buffer is - * allocated and the hardware unit is configured to point to the - * new command queue. - * - * @queue_id: Hardware command queue to initialize. - * @max_depth: Maximum outstanding commands that can be queued. - * @fpa_pool: FPA pool the command queues should come from. - * @pool_size: Size of each buffer in the FPA pool (bytes) - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, - int max_depth, int fpa_pool, - int pool_size); - -/** - * Shutdown a queue a free it's command buffers to the FPA. The - * hardware connected to the queue must be stopped before this - * function is called. - * - * @queue_id: Queue to shutdown - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id); - -/** - * Return the number of command words pending in the queue. This - * function may be relatively slow for some hardware units. - * - * @queue_id: Hardware command queue to query - * - * Returns Number of outstanding commands - */ -int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id); - -/** - * Return the command buffer to be written to. The purpose of this - * function is to allow CVMX routine access t othe low level buffer - * for initial hardware setup. User applications should not call this - * function directly. - * - * @queue_id: Command queue to query - * - * Returns Command buffer or NULL on failure - */ -void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id); - -/** - * Get the index into the state arrays for the supplied queue id. - * - * @queue_id: Queue ID to get an index for - * - * Returns Index into the state arrays - */ -static inline int __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id) -{ - /* - * Warning: This code currently only works with devices that - * have 256 queues or less. Devices with more than 16 queues - * are laid out in memory to allow cores quick access to - * every 16th queue. This reduces cache thrashing when you are - * running 16 queues per port to support lockless operation. - */ - int unit = queue_id >> 16; - int q = (queue_id >> 4) & 0xf; - int core = queue_id & 0xf; - return unit * 256 + core * 16 + q; -} - -/** - * Lock the supplied queue so nobody else is updating it at the same - * time as us. - * - * @queue_id: Queue ID to lock - * @qptr: Pointer to the queue's global state - */ -static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id, - __cvmx_cmd_queue_state_t *qptr) -{ - extern __cvmx_cmd_queue_all_state_t - *__cvmx_cmd_queue_state_ptr; - int tmp; - int my_ticket; - prefetch(qptr); - asm volatile ( - ".set push\n" - ".set noreorder\n" - "1:\n" - /* Atomic add one to ticket_ptr */ - "ll %[my_ticket], %[ticket_ptr]\n" - /* and store the original value */ - "li %[ticket], 1\n" - /* in my_ticket */ - "baddu %[ticket], %[my_ticket]\n" - "sc %[ticket], %[ticket_ptr]\n" - "beqz %[ticket], 1b\n" - " nop\n" - /* Load the current now_serving ticket */ - "lbu %[ticket], %[now_serving]\n" - "2:\n" - /* Jump out if now_serving == my_ticket */ - "beq %[ticket], %[my_ticket], 4f\n" - /* Find out how many tickets are in front of me */ - " subu %[ticket], %[my_ticket], %[ticket]\n" - /* Use tickets in front of me minus one to delay */ - "subu %[ticket], 1\n" - /* Delay will be ((tickets in front)-1)*32 loops */ - "cins %[ticket], %[ticket], 5, 7\n" - "3:\n" - /* Loop here until our ticket might be up */ - "bnez %[ticket], 3b\n" - " subu %[ticket], 1\n" - /* Jump back up to check out ticket again */ - "b 2b\n" - /* Load the current now_serving ticket */ - " lbu %[ticket], %[now_serving]\n" - "4:\n" - ".set pop\n" : - [ticket_ptr] "=m"(__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]), - [now_serving] "=m"(qptr->now_serving), [ticket] "=r"(tmp), - [my_ticket] "=r"(my_ticket) - ); -} - -/** - * Unlock the queue, flushing all writes. - * - * @qptr: Queue to unlock - */ -static inline void __cvmx_cmd_queue_unlock(__cvmx_cmd_queue_state_t *qptr) -{ - qptr->now_serving++; - CVMX_SYNCWS; -} - -/** - * Get the queue state structure for the given queue id - * - * @queue_id: Queue id to get - * - * Returns Queue structure or NULL on failure - */ -static inline __cvmx_cmd_queue_state_t - *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id) -{ - extern __cvmx_cmd_queue_all_state_t - *__cvmx_cmd_queue_state_ptr; - return &__cvmx_cmd_queue_state_ptr-> - state[__cvmx_cmd_queue_get_index(queue_id)]; -} - -/** - * Write an arbitrary number of command words to a command queue. - * This is a generic function; the fixed number of command word - * functions yield higher performance. - * - * @queue_id: Hardware command queue to write to - * @use_locking: - * Use internal locking to ensure exclusive access for queue - * updates. If you don't use this locking you must ensure - * exclusivity some other way. Locking is strongly recommended. - * @cmd_count: Number of command words to write - * @cmds: Array of commands to write - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write(cvmx_cmd_queue_id_t - queue_id, - int use_locking, - int cmd_count, - uint64_t *cmds) -{ - __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); - - /* Make sure nobody else is updating the same queue */ - if (likely(use_locking)) - __cvmx_cmd_queue_lock(queue_id, qptr); - - /* - * If a max queue length was specified then make sure we don't - * exceed it. If any part of the command would be below the - * limit we allow it. - */ - if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && unlikely(qptr->max_depth)) { - if (unlikely - (cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth)) { - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_FULL; - } - } - - /* - * Normally there is plenty of room in the current buffer for - * the command. - */ - if (likely(qptr->index + cmd_count < qptr->pool_size_m1)) { - uint64_t *ptr = - (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> - base_ptr_div128 << 7); - ptr += qptr->index; - qptr->index += cmd_count; - while (cmd_count--) - *ptr++ = *cmds++; - } else { - uint64_t *ptr; - int count; - /* - * We need a new command buffer. Fail if there isn't - * one available. - */ - uint64_t *new_buffer = - (uint64_t *) cvmx_fpa_alloc(qptr->fpa_pool); - if (unlikely(new_buffer == NULL)) { - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_NO_MEMORY; - } - ptr = - (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> - base_ptr_div128 << 7); - /* - * Figure out how many command words will fit in this - * buffer. One location will be needed for the next - * buffer pointer. - */ - count = qptr->pool_size_m1 - qptr->index; - ptr += qptr->index; - cmd_count -= count; - while (count--) - *ptr++ = *cmds++; - *ptr = cvmx_ptr_to_phys(new_buffer); - /* - * The current buffer is full and has a link to the - * next buffer. Time to write the rest of the commands - * into the new buffer. - */ - qptr->base_ptr_div128 = *ptr >> 7; - qptr->index = cmd_count; - ptr = new_buffer; - while (cmd_count--) - *ptr++ = *cmds++; - } - - /* All updates are complete. Release the lock and return */ - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_SUCCESS; -} - -/** - * Simple function to write two command words to a command - * queue. - * - * @queue_id: Hardware command queue to write to - * @use_locking: - * Use internal locking to ensure exclusive access for queue - * updates. If you don't use this locking you must ensure - * exclusivity some other way. Locking is strongly recommended. - * @cmd1: Command - * @cmd2: Command - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write2(cvmx_cmd_queue_id_t - queue_id, - int use_locking, - uint64_t cmd1, - uint64_t cmd2) -{ - __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); - - /* Make sure nobody else is updating the same queue */ - if (likely(use_locking)) - __cvmx_cmd_queue_lock(queue_id, qptr); - - /* - * If a max queue length was specified then make sure we don't - * exceed it. If any part of the command would be below the - * limit we allow it. - */ - if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && unlikely(qptr->max_depth)) { - if (unlikely - (cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth)) { - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_FULL; - } - } - - /* - * Normally there is plenty of room in the current buffer for - * the command. - */ - if (likely(qptr->index + 2 < qptr->pool_size_m1)) { - uint64_t *ptr = - (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> - base_ptr_div128 << 7); - ptr += qptr->index; - qptr->index += 2; - ptr[0] = cmd1; - ptr[1] = cmd2; - } else { - uint64_t *ptr; - /* - * Figure out how many command words will fit in this - * buffer. One location will be needed for the next - * buffer pointer. - */ - int count = qptr->pool_size_m1 - qptr->index; - /* - * We need a new command buffer. Fail if there isn't - * one available. - */ - uint64_t *new_buffer = - (uint64_t *) cvmx_fpa_alloc(qptr->fpa_pool); - if (unlikely(new_buffer == NULL)) { - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_NO_MEMORY; - } - count--; - ptr = - (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> - base_ptr_div128 << 7); - ptr += qptr->index; - *ptr++ = cmd1; - if (likely(count)) - *ptr++ = cmd2; - *ptr = cvmx_ptr_to_phys(new_buffer); - /* - * The current buffer is full and has a link to the - * next buffer. Time to write the rest of the commands - * into the new buffer. - */ - qptr->base_ptr_div128 = *ptr >> 7; - qptr->index = 0; - if (unlikely(count == 0)) { - qptr->index = 1; - new_buffer[0] = cmd2; - } - } - - /* All updates are complete. Release the lock and return */ - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_SUCCESS; -} - -/** - * Simple function to write three command words to a command - * queue. - * - * @queue_id: Hardware command queue to write to - * @use_locking: - * Use internal locking to ensure exclusive access for queue - * updates. If you don't use this locking you must ensure - * exclusivity some other way. Locking is strongly recommended. - * @cmd1: Command - * @cmd2: Command - * @cmd3: Command - * - * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code - */ -static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write3(cvmx_cmd_queue_id_t - queue_id, - int use_locking, - uint64_t cmd1, - uint64_t cmd2, - uint64_t cmd3) -{ - __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id); - - /* Make sure nobody else is updating the same queue */ - if (likely(use_locking)) - __cvmx_cmd_queue_lock(queue_id, qptr); - - /* - * If a max queue length was specified then make sure we don't - * exceed it. If any part of the command would be below the - * limit we allow it. - */ - if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && unlikely(qptr->max_depth)) { - if (unlikely - (cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth)) { - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_FULL; - } - } - - /* - * Normally there is plenty of room in the current buffer for - * the command. - */ - if (likely(qptr->index + 3 < qptr->pool_size_m1)) { - uint64_t *ptr = - (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> - base_ptr_div128 << 7); - ptr += qptr->index; - qptr->index += 3; - ptr[0] = cmd1; - ptr[1] = cmd2; - ptr[2] = cmd3; - } else { - uint64_t *ptr; - /* - * Figure out how many command words will fit in this - * buffer. One location will be needed for the next - * buffer pointer - */ - int count = qptr->pool_size_m1 - qptr->index; - /* - * We need a new command buffer. Fail if there isn't - * one available - */ - uint64_t *new_buffer = - (uint64_t *) cvmx_fpa_alloc(qptr->fpa_pool); - if (unlikely(new_buffer == NULL)) { - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_NO_MEMORY; - } - count--; - ptr = - (uint64_t *) cvmx_phys_to_ptr((uint64_t) qptr-> - base_ptr_div128 << 7); - ptr += qptr->index; - *ptr++ = cmd1; - if (count) { - *ptr++ = cmd2; - if (count > 1) - *ptr++ = cmd3; - } - *ptr = cvmx_ptr_to_phys(new_buffer); - /* - * The current buffer is full and has a link to the - * next buffer. Time to write the rest of the commands - * into the new buffer. - */ - qptr->base_ptr_div128 = *ptr >> 7; - qptr->index = 0; - ptr = new_buffer; - if (count == 0) { - *ptr++ = cmd2; - qptr->index++; - } - if (count < 2) { - *ptr++ = cmd3; - qptr->index++; - } - } - - /* All updates are complete. Release the lock and return */ - if (likely(use_locking)) - __cvmx_cmd_queue_unlock(qptr); - return CVMX_CMD_QUEUE_SUCCESS; -} - -#endif /* __CVMX_CMD_QUEUE_H__ */ diff --git a/drivers/staging/octeon/cvmx-config.h b/drivers/staging/octeon/cvmx-config.h deleted file mode 100644 index 078a520481cf..000000000000 --- a/drivers/staging/octeon/cvmx-config.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef __CVMX_CONFIG_H__ -#define __CVMX_CONFIG_H__ - -/************************* Config Specific Defines ************************/ -#define CVMX_LLM_NUM_PORTS 1 -#define CVMX_NULL_POINTER_PROTECT 1 -#define CVMX_ENABLE_DEBUG_PRINTS 1 -/* PKO queues per port for interface 0 (ports 0-15) */ -#define CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 1 -/* PKO queues per port for interface 1 (ports 16-31) */ -#define CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 1 -/* Limit on the number of PKO ports enabled for interface 0 */ -#define CVMX_PKO_MAX_PORTS_INTERFACE0 CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 -/* Limit on the number of PKO ports enabled for interface 1 */ -#define CVMX_PKO_MAX_PORTS_INTERFACE1 CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 -/* PKO queues per port for PCI (ports 32-35) */ -#define CVMX_PKO_QUEUES_PER_PORT_PCI 1 -/* PKO queues per port for Loop devices (ports 36-39) */ -#define CVMX_PKO_QUEUES_PER_PORT_LOOP 1 - -/************************* FPA allocation *********************************/ -/* Pool sizes in bytes, must be multiple of a cache line */ -#define CVMX_FPA_POOL_0_SIZE (16 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_1_SIZE (1 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_2_SIZE (8 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_3_SIZE (0 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_4_SIZE (0 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_5_SIZE (0 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_6_SIZE (0 * CVMX_CACHE_LINE_SIZE) -#define CVMX_FPA_POOL_7_SIZE (0 * CVMX_CACHE_LINE_SIZE) - -/* Pools in use */ -/* Packet buffers */ -#define CVMX_FPA_PACKET_POOL (0) -#define CVMX_FPA_PACKET_POOL_SIZE CVMX_FPA_POOL_0_SIZE -/* Work queue entrys */ -#define CVMX_FPA_WQE_POOL (1) -#define CVMX_FPA_WQE_POOL_SIZE CVMX_FPA_POOL_1_SIZE -/* PKO queue command buffers */ -#define CVMX_FPA_OUTPUT_BUFFER_POOL (2) -#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE CVMX_FPA_POOL_2_SIZE - -/************************* FAU allocation ********************************/ -/* The fetch and add registers are allocated here. They are arranged - * in order of descending size so that all alignment constraints are - * automatically met. The enums are linked so that the following enum - * continues allocating where the previous one left off, so the - * numbering within each enum always starts with zero. The macros - * take care of the address increment size, so the values entered - * always increase by 1. FAU registers are accessed with byte - * addresses. - */ - -#define CVMX_FAU_REG_64_ADDR(x) ((x << 3) + CVMX_FAU_REG_64_START) -typedef enum { - CVMX_FAU_REG_64_START = 0, - CVMX_FAU_REG_64_END = CVMX_FAU_REG_64_ADDR(0), -} cvmx_fau_reg_64_t; - -#define CVMX_FAU_REG_32_ADDR(x) ((x << 2) + CVMX_FAU_REG_32_START) -typedef enum { - CVMX_FAU_REG_32_START = CVMX_FAU_REG_64_END, - CVMX_FAU_REG_32_END = CVMX_FAU_REG_32_ADDR(0), -} cvmx_fau_reg_32_t; - -#define CVMX_FAU_REG_16_ADDR(x) ((x << 1) + CVMX_FAU_REG_16_START) -typedef enum { - CVMX_FAU_REG_16_START = CVMX_FAU_REG_32_END, - CVMX_FAU_REG_16_END = CVMX_FAU_REG_16_ADDR(0), -} cvmx_fau_reg_16_t; - -#define CVMX_FAU_REG_8_ADDR(x) ((x) + CVMX_FAU_REG_8_START) -typedef enum { - CVMX_FAU_REG_8_START = CVMX_FAU_REG_16_END, - CVMX_FAU_REG_8_END = CVMX_FAU_REG_8_ADDR(0), -} cvmx_fau_reg_8_t; - -/* - * The name CVMX_FAU_REG_AVAIL_BASE is provided to indicate the first - * available FAU address that is not allocated in cvmx-config.h. This - * is 64 bit aligned. - */ -#define CVMX_FAU_REG_AVAIL_BASE ((CVMX_FAU_REG_8_END + 0x7) & (~0x7ULL)) -#define CVMX_FAU_REG_END (2048) - -/********************** scratch memory allocation *************************/ -/* Scratchpad memory allocation. Note that these are byte memory - * addresses. Some uses of scratchpad (IOBDMA for example) require - * the use of 8-byte aligned addresses, so proper alignment needs to - * be taken into account. - */ -/* Generic scratch iobdma area */ -#define CVMX_SCR_SCRATCH (0) -/* First location available after cvmx-config.h allocated region. */ -#define CVMX_SCR_REG_AVAIL_BASE (8) - -/* - * CVMX_HELPER_FIRST_MBUFF_SKIP is the number of bytes to reserve - * before the beginning of the packet. If necessary, override the - * default here. See the IPD section of the hardware manual for MBUFF - * SKIP details. - */ -#define CVMX_HELPER_FIRST_MBUFF_SKIP 184 - -/* - * CVMX_HELPER_NOT_FIRST_MBUFF_SKIP is the number of bytes to reserve - * in each chained packet element. If necessary, override the default - * here. - */ -#define CVMX_HELPER_NOT_FIRST_MBUFF_SKIP 0 - -/* - * CVMX_HELPER_ENABLE_BACK_PRESSURE controls whether back pressure is - * enabled for all input ports. This controls if IPD sends - * backpressure to all ports if Octeon's FPA pools don't have enough - * packet or work queue entries. Even when this is off, it is still - * possible to get backpressure from individual hardware ports. When - * configuring backpressure, also check - * CVMX_HELPER_DISABLE_*_BACKPRESSURE below. If necessary, override - * the default here. - */ -#define CVMX_HELPER_ENABLE_BACK_PRESSURE 1 - -/* - * CVMX_HELPER_ENABLE_IPD controls if the IPD is enabled in the helper - * function. Once it is enabled the hardware starts accepting - * packets. You might want to skip the IPD enable if configuration - * changes are need from the default helper setup. If necessary, - * override the default here. - */ -#define CVMX_HELPER_ENABLE_IPD 0 - -/* - * CVMX_HELPER_INPUT_TAG_TYPE selects the type of tag that the IPD assigns - * to incoming packets. - */ -#define CVMX_HELPER_INPUT_TAG_TYPE CVMX_POW_TAG_TYPE_ORDERED - -#define CVMX_ENABLE_PARAMETER_CHECKING 0 - -/* - * The following select which fields are used by the PIP to generate - * the tag on INPUT - * 0: don't include - * 1: include - */ -#define CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP 0 -#define CVMX_HELPER_INPUT_TAG_IPV6_DST_IP 0 -#define CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT 0 -#define CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT 0 -#define CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER 0 -#define CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP 0 -#define CVMX_HELPER_INPUT_TAG_IPV4_DST_IP 0 -#define CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT 0 -#define CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT 0 -#define CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL 0 -#define CVMX_HELPER_INPUT_TAG_INPUT_PORT 1 - -/* Select skip mode for input ports */ -#define CVMX_HELPER_INPUT_PORT_SKIP_MODE CVMX_PIP_PORT_CFG_MODE_SKIPL2 - -/* - * Force backpressure to be disabled. This overrides all other - * backpressure configuration. - */ -#define CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE 0 - -#endif /* __CVMX_CONFIG_H__ */ - diff --git a/drivers/staging/octeon/cvmx-dbg-defs.h b/drivers/staging/octeon/cvmx-dbg-defs.h deleted file mode 100644 index abbf42d05e5a..000000000000 --- a/drivers/staging/octeon/cvmx-dbg-defs.h +++ /dev/null @@ -1,72 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_DBG_DEFS_H__ -#define __CVMX_DBG_DEFS_H__ - -#define CVMX_DBG_DATA \ - CVMX_ADD_IO_SEG(0x00011F00000001E8ull) - -union cvmx_dbg_data { - uint64_t u64; - struct cvmx_dbg_data_s { - uint64_t reserved_23_63:41; - uint64_t c_mul:5; - uint64_t dsel_ext:1; - uint64_t data:17; - } s; - struct cvmx_dbg_data_cn30xx { - uint64_t reserved_31_63:33; - uint64_t pll_mul:3; - uint64_t reserved_23_27:5; - uint64_t c_mul:5; - uint64_t dsel_ext:1; - uint64_t data:17; - } cn30xx; - struct cvmx_dbg_data_cn30xx cn31xx; - struct cvmx_dbg_data_cn38xx { - uint64_t reserved_29_63:35; - uint64_t d_mul:4; - uint64_t dclk_mul2:1; - uint64_t cclk_div2:1; - uint64_t c_mul:5; - uint64_t dsel_ext:1; - uint64_t data:17; - } cn38xx; - struct cvmx_dbg_data_cn38xx cn38xxp2; - struct cvmx_dbg_data_cn30xx cn50xx; - struct cvmx_dbg_data_cn58xx { - uint64_t reserved_29_63:35; - uint64_t rem:6; - uint64_t c_mul:5; - uint64_t dsel_ext:1; - uint64_t data:17; - } cn58xx; - struct cvmx_dbg_data_cn58xx cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-fau.h b/drivers/staging/octeon/cvmx-fau.h deleted file mode 100644 index a6939fc8ba18..000000000000 --- a/drivers/staging/octeon/cvmx-fau.h +++ /dev/null @@ -1,597 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Interface to the hardware Fetch and Add Unit. - */ - -#ifndef __CVMX_FAU_H__ -#define __CVMX_FAU_H__ - -/* - * Octeon Fetch and Add Unit (FAU) - */ - -#define CVMX_FAU_LOAD_IO_ADDRESS cvmx_build_io_address(0x1e, 0) -#define CVMX_FAU_BITS_SCRADDR 63, 56 -#define CVMX_FAU_BITS_LEN 55, 48 -#define CVMX_FAU_BITS_INEVAL 35, 14 -#define CVMX_FAU_BITS_TAGWAIT 13, 13 -#define CVMX_FAU_BITS_NOADD 13, 13 -#define CVMX_FAU_BITS_SIZE 12, 11 -#define CVMX_FAU_BITS_REGISTER 10, 0 - -typedef enum { - CVMX_FAU_OP_SIZE_8 = 0, - CVMX_FAU_OP_SIZE_16 = 1, - CVMX_FAU_OP_SIZE_32 = 2, - CVMX_FAU_OP_SIZE_64 = 3 -} cvmx_fau_op_size_t; - -/** - * Tagwait return definition. If a timeout occurs, the error - * bit will be set. Otherwise the value of the register before - * the update will be returned. - */ -typedef struct { - uint64_t error:1; - int64_t value:63; -} cvmx_fau_tagwait64_t; - -/** - * Tagwait return definition. If a timeout occurs, the error - * bit will be set. Otherwise the value of the register before - * the update will be returned. - */ -typedef struct { - uint64_t error:1; - int32_t value:31; -} cvmx_fau_tagwait32_t; - -/** - * Tagwait return definition. If a timeout occurs, the error - * bit will be set. Otherwise the value of the register before - * the update will be returned. - */ -typedef struct { - uint64_t error:1; - int16_t value:15; -} cvmx_fau_tagwait16_t; - -/** - * Tagwait return definition. If a timeout occurs, the error - * bit will be set. Otherwise the value of the register before - * the update will be returned. - */ -typedef struct { - uint64_t error:1; - int8_t value:7; -} cvmx_fau_tagwait8_t; - -/** - * Asynchronous tagwait return definition. If a timeout occurs, - * the error bit will be set. Otherwise the value of the - * register before the update will be returned. - */ -typedef union { - uint64_t u64; - struct { - uint64_t invalid:1; - uint64_t data:63; /* unpredictable if invalid is set */ - } s; -} cvmx_fau_async_tagwait_result_t; - -/** - * Builds a store I/O address for writing to the FAU - * - * @noadd: 0 = Store value is atomically added to the current value - * 1 = Store value is atomically written over the current value - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * - Step by 4 for 32 bit access. - * - Step by 8 for 64 bit access. - * Returns Address to store for atomic update - */ -static inline uint64_t __cvmx_fau_store_address(uint64_t noadd, uint64_t reg) -{ - return CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | - cvmx_build_bits(CVMX_FAU_BITS_NOADD, noadd) | - cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg); -} - -/** - * Builds a I/O address for accessing the FAU - * - * @tagwait: Should the atomic add wait for the current tag switch - * operation to complete. - * - 0 = Don't wait - * - 1 = Wait for tag switch to complete - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * - Step by 4 for 32 bit access. - * - Step by 8 for 64 bit access. - * @value: Signed value to add. - * Note: When performing 32 and 64 bit access, only the low - * 22 bits are available. - * Returns Address to read from for atomic update - */ -static inline uint64_t __cvmx_fau_atomic_address(uint64_t tagwait, uint64_t reg, - int64_t value) -{ - return CVMX_ADD_IO_SEG(CVMX_FAU_LOAD_IO_ADDRESS) | - cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | - cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | - cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg); -} - -/** - * Perform an atomic 64 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 8 for 64 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns Value of the register before the update - */ -static inline int64_t cvmx_fau_fetch_and_add64(cvmx_fau_reg_64_t reg, - int64_t value) -{ - return cvmx_read64_int64(__cvmx_fau_atomic_address(0, reg, value)); -} - -/** - * Perform an atomic 32 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 4 for 32 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns Value of the register before the update - */ -static inline int32_t cvmx_fau_fetch_and_add32(cvmx_fau_reg_32_t reg, - int32_t value) -{ - return cvmx_read64_int32(__cvmx_fau_atomic_address(0, reg, value)); -} - -/** - * Perform an atomic 16 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * @value: Signed value to add. - * Returns Value of the register before the update - */ -static inline int16_t cvmx_fau_fetch_and_add16(cvmx_fau_reg_16_t reg, - int16_t value) -{ - return cvmx_read64_int16(__cvmx_fau_atomic_address(0, reg, value)); -} - -/** - * Perform an atomic 8 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * @value: Signed value to add. - * Returns Value of the register before the update - */ -static inline int8_t cvmx_fau_fetch_and_add8(cvmx_fau_reg_8_t reg, int8_t value) -{ - return cvmx_read64_int8(__cvmx_fau_atomic_address(0, reg, value)); -} - -/** - * Perform an atomic 64 bit add after the current tag switch - * completes - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 8 for 64 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns If a timeout occurs, the error bit will be set. Otherwise - * the value of the register before the update will be - * returned - */ -static inline cvmx_fau_tagwait64_t -cvmx_fau_tagwait_fetch_and_add64(cvmx_fau_reg_64_t reg, int64_t value) -{ - union { - uint64_t i64; - cvmx_fau_tagwait64_t t; - } result; - result.i64 = - cvmx_read64_int64(__cvmx_fau_atomic_address(1, reg, value)); - return result.t; -} - -/** - * Perform an atomic 32 bit add after the current tag switch - * completes - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 4 for 32 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns If a timeout occurs, the error bit will be set. Otherwise - * the value of the register before the update will be - * returned - */ -static inline cvmx_fau_tagwait32_t -cvmx_fau_tagwait_fetch_and_add32(cvmx_fau_reg_32_t reg, int32_t value) -{ - union { - uint64_t i32; - cvmx_fau_tagwait32_t t; - } result; - result.i32 = - cvmx_read64_int32(__cvmx_fau_atomic_address(1, reg, value)); - return result.t; -} - -/** - * Perform an atomic 16 bit add after the current tag switch - * completes - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * @value: Signed value to add. - * Returns If a timeout occurs, the error bit will be set. Otherwise - * the value of the register before the update will be - * returned - */ -static inline cvmx_fau_tagwait16_t -cvmx_fau_tagwait_fetch_and_add16(cvmx_fau_reg_16_t reg, int16_t value) -{ - union { - uint64_t i16; - cvmx_fau_tagwait16_t t; - } result; - result.i16 = - cvmx_read64_int16(__cvmx_fau_atomic_address(1, reg, value)); - return result.t; -} - -/** - * Perform an atomic 8 bit add after the current tag switch - * completes - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * @value: Signed value to add. - * Returns If a timeout occurs, the error bit will be set. Otherwise - * the value of the register before the update will be - * returned - */ -static inline cvmx_fau_tagwait8_t -cvmx_fau_tagwait_fetch_and_add8(cvmx_fau_reg_8_t reg, int8_t value) -{ - union { - uint64_t i8; - cvmx_fau_tagwait8_t t; - } result; - result.i8 = cvmx_read64_int8(__cvmx_fau_atomic_address(1, reg, value)); - return result.t; -} - -/** - * Builds I/O data for async operations - * - * @scraddr: Scratch pad byte address to write to. Must be 8 byte aligned - * @value: Signed value to add. - * Note: When performing 32 and 64 bit access, only the low - * 22 bits are available. - * @tagwait: Should the atomic add wait for the current tag switch - * operation to complete. - * - 0 = Don't wait - * - 1 = Wait for tag switch to complete - * @size: The size of the operation: - * - CVMX_FAU_OP_SIZE_8 (0) = 8 bits - * - CVMX_FAU_OP_SIZE_16 (1) = 16 bits - * - CVMX_FAU_OP_SIZE_32 (2) = 32 bits - * - CVMX_FAU_OP_SIZE_64 (3) = 64 bits - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * - Step by 4 for 32 bit access. - * - Step by 8 for 64 bit access. - * Returns Data to write using cvmx_send_single - */ -static inline uint64_t __cvmx_fau_iobdma_data(uint64_t scraddr, int64_t value, - uint64_t tagwait, - cvmx_fau_op_size_t size, - uint64_t reg) -{ - return CVMX_FAU_LOAD_IO_ADDRESS | - cvmx_build_bits(CVMX_FAU_BITS_SCRADDR, scraddr >> 3) | - cvmx_build_bits(CVMX_FAU_BITS_LEN, 1) | - cvmx_build_bits(CVMX_FAU_BITS_INEVAL, value) | - cvmx_build_bits(CVMX_FAU_BITS_TAGWAIT, tagwait) | - cvmx_build_bits(CVMX_FAU_BITS_SIZE, size) | - cvmx_build_bits(CVMX_FAU_BITS_REGISTER, reg); -} - -/** - * Perform an async atomic 64 bit add. The old value is - * placed in the scratch memory at byte address scraddr. - * - * @scraddr: Scratch memory byte address to put response in. - * Must be 8 byte aligned. - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 8 for 64 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_fetch_and_add64(uint64_t scraddr, - cvmx_fau_reg_64_t reg, - int64_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 0, CVMX_FAU_OP_SIZE_64, reg)); -} - -/** - * Perform an async atomic 32 bit add. The old value is - * placed in the scratch memory at byte address scraddr. - * - * @scraddr: Scratch memory byte address to put response in. - * Must be 8 byte aligned. - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 4 for 32 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_fetch_and_add32(uint64_t scraddr, - cvmx_fau_reg_32_t reg, - int32_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 0, CVMX_FAU_OP_SIZE_32, reg)); -} - -/** - * Perform an async atomic 16 bit add. The old value is - * placed in the scratch memory at byte address scraddr. - * - * @scraddr: Scratch memory byte address to put response in. - * Must be 8 byte aligned. - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * @value: Signed value to add. - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_fetch_and_add16(uint64_t scraddr, - cvmx_fau_reg_16_t reg, - int16_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 0, CVMX_FAU_OP_SIZE_16, reg)); -} - -/** - * Perform an async atomic 8 bit add. The old value is - * placed in the scratch memory at byte address scraddr. - * - * @scraddr: Scratch memory byte address to put response in. - * Must be 8 byte aligned. - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * @value: Signed value to add. - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_fetch_and_add8(uint64_t scraddr, - cvmx_fau_reg_8_t reg, - int8_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 0, CVMX_FAU_OP_SIZE_8, reg)); -} - -/** - * Perform an async atomic 64 bit add after the current tag - * switch completes. - * - * @scraddr: Scratch memory byte address to put response in. Must be - * 8 byte aligned. If a timeout occurs, the error bit (63) - * will be set. Otherwise the value of the register before - * the update will be returned - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 8 for 64 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_tagwait_fetch_and_add64(uint64_t scraddr, - cvmx_fau_reg_64_t reg, - int64_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 1, CVMX_FAU_OP_SIZE_64, reg)); -} - -/** - * Perform an async atomic 32 bit add after the current tag - * switch completes. - * - * @scraddr: Scratch memory byte address to put response in. Must be - * 8 byte aligned. If a timeout occurs, the error bit (63) - * will be set. Otherwise the value of the register before - * the update will be returned - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 4 for 32 bit access. - * @value: Signed value to add. - * Note: Only the low 22 bits are available. - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_tagwait_fetch_and_add32(uint64_t scraddr, - cvmx_fau_reg_32_t reg, - int32_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 1, CVMX_FAU_OP_SIZE_32, reg)); -} - -/** - * Perform an async atomic 16 bit add after the current tag - * switch completes. - * - * @scraddr: Scratch memory byte address to put response in. Must be - * 8 byte aligned. If a timeout occurs, the error bit (63) - * will be set. Otherwise the value of the register before - * the update will be returned - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * @value: Signed value to add. - * - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_tagwait_fetch_and_add16(uint64_t scraddr, - cvmx_fau_reg_16_t reg, - int16_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 1, CVMX_FAU_OP_SIZE_16, reg)); -} - -/** - * Perform an async atomic 8 bit add after the current tag - * switch completes. - * - * @scraddr: Scratch memory byte address to put response in. Must be - * 8 byte aligned. If a timeout occurs, the error bit (63) - * will be set. Otherwise the value of the register before - * the update will be returned - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * @value: Signed value to add. - * - * Returns Placed in the scratch pad register - */ -static inline void cvmx_fau_async_tagwait_fetch_and_add8(uint64_t scraddr, - cvmx_fau_reg_8_t reg, - int8_t value) -{ - cvmx_send_single(__cvmx_fau_iobdma_data - (scraddr, value, 1, CVMX_FAU_OP_SIZE_8, reg)); -} - -/** - * Perform an atomic 64 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 8 for 64 bit access. - * @value: Signed value to add. - */ -static inline void cvmx_fau_atomic_add64(cvmx_fau_reg_64_t reg, int64_t value) -{ - cvmx_write64_int64(__cvmx_fau_store_address(0, reg), value); -} - -/** - * Perform an atomic 32 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 4 for 32 bit access. - * @value: Signed value to add. - */ -static inline void cvmx_fau_atomic_add32(cvmx_fau_reg_32_t reg, int32_t value) -{ - cvmx_write64_int32(__cvmx_fau_store_address(0, reg), value); -} - -/** - * Perform an atomic 16 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * @value: Signed value to add. - */ -static inline void cvmx_fau_atomic_add16(cvmx_fau_reg_16_t reg, int16_t value) -{ - cvmx_write64_int16(__cvmx_fau_store_address(0, reg), value); -} - -/** - * Perform an atomic 8 bit add - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * @value: Signed value to add. - */ -static inline void cvmx_fau_atomic_add8(cvmx_fau_reg_8_t reg, int8_t value) -{ - cvmx_write64_int8(__cvmx_fau_store_address(0, reg), value); -} - -/** - * Perform an atomic 64 bit write - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 8 for 64 bit access. - * @value: Signed value to write. - */ -static inline void cvmx_fau_atomic_write64(cvmx_fau_reg_64_t reg, int64_t value) -{ - cvmx_write64_int64(__cvmx_fau_store_address(1, reg), value); -} - -/** - * Perform an atomic 32 bit write - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 4 for 32 bit access. - * @value: Signed value to write. - */ -static inline void cvmx_fau_atomic_write32(cvmx_fau_reg_32_t reg, int32_t value) -{ - cvmx_write64_int32(__cvmx_fau_store_address(1, reg), value); -} - -/** - * Perform an atomic 16 bit write - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * - Step by 2 for 16 bit access. - * @value: Signed value to write. - */ -static inline void cvmx_fau_atomic_write16(cvmx_fau_reg_16_t reg, int16_t value) -{ - cvmx_write64_int16(__cvmx_fau_store_address(1, reg), value); -} - -/** - * Perform an atomic 8 bit write - * - * @reg: FAU atomic register to access. 0 <= reg < 2048. - * @value: Signed value to write. - */ -static inline void cvmx_fau_atomic_write8(cvmx_fau_reg_8_t reg, int8_t value) -{ - cvmx_write64_int8(__cvmx_fau_store_address(1, reg), value); -} - -#endif /* __CVMX_FAU_H__ */ diff --git a/drivers/staging/octeon/cvmx-fpa-defs.h b/drivers/staging/octeon/cvmx-fpa-defs.h deleted file mode 100644 index bf5546b90110..000000000000 --- a/drivers/staging/octeon/cvmx-fpa-defs.h +++ /dev/null @@ -1,403 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_FPA_DEFS_H__ -#define __CVMX_FPA_DEFS_H__ - -#define CVMX_FPA_BIST_STATUS \ - CVMX_ADD_IO_SEG(0x00011800280000E8ull) -#define CVMX_FPA_CTL_STATUS \ - CVMX_ADD_IO_SEG(0x0001180028000050ull) -#define CVMX_FPA_FPF0_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000000ull) -#define CVMX_FPA_FPF0_SIZE \ - CVMX_ADD_IO_SEG(0x0001180028000058ull) -#define CVMX_FPA_FPF1_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000008ull) -#define CVMX_FPA_FPF2_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000010ull) -#define CVMX_FPA_FPF3_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000018ull) -#define CVMX_FPA_FPF4_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000020ull) -#define CVMX_FPA_FPF5_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000028ull) -#define CVMX_FPA_FPF6_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000030ull) -#define CVMX_FPA_FPF7_MARKS \ - CVMX_ADD_IO_SEG(0x0001180028000038ull) -#define CVMX_FPA_FPFX_MARKS(offset) \ - CVMX_ADD_IO_SEG(0x0001180028000008ull + (((offset) & 7) * 8) - 8 * 1) -#define CVMX_FPA_FPFX_SIZE(offset) \ - CVMX_ADD_IO_SEG(0x0001180028000060ull + (((offset) & 7) * 8) - 8 * 1) -#define CVMX_FPA_INT_ENB \ - CVMX_ADD_IO_SEG(0x0001180028000048ull) -#define CVMX_FPA_INT_SUM \ - CVMX_ADD_IO_SEG(0x0001180028000040ull) -#define CVMX_FPA_QUE0_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x00011800280000F0ull) -#define CVMX_FPA_QUE1_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x00011800280000F8ull) -#define CVMX_FPA_QUE2_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x0001180028000100ull) -#define CVMX_FPA_QUE3_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x0001180028000108ull) -#define CVMX_FPA_QUE4_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x0001180028000110ull) -#define CVMX_FPA_QUE5_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x0001180028000118ull) -#define CVMX_FPA_QUE6_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x0001180028000120ull) -#define CVMX_FPA_QUE7_PAGE_INDEX \ - CVMX_ADD_IO_SEG(0x0001180028000128ull) -#define CVMX_FPA_QUEX_AVAILABLE(offset) \ - CVMX_ADD_IO_SEG(0x0001180028000098ull + (((offset) & 7) * 8)) -#define CVMX_FPA_QUEX_PAGE_INDEX(offset) \ - CVMX_ADD_IO_SEG(0x00011800280000F0ull + (((offset) & 7) * 8)) -#define CVMX_FPA_QUE_ACT \ - CVMX_ADD_IO_SEG(0x0001180028000138ull) -#define CVMX_FPA_QUE_EXP \ - CVMX_ADD_IO_SEG(0x0001180028000130ull) -#define CVMX_FPA_WART_CTL \ - CVMX_ADD_IO_SEG(0x00011800280000D8ull) -#define CVMX_FPA_WART_STATUS \ - CVMX_ADD_IO_SEG(0x00011800280000E0ull) - -union cvmx_fpa_bist_status { - uint64_t u64; - struct cvmx_fpa_bist_status_s { - uint64_t reserved_5_63:59; - uint64_t frd:1; - uint64_t fpf0:1; - uint64_t fpf1:1; - uint64_t ffr:1; - uint64_t fdr:1; - } s; - struct cvmx_fpa_bist_status_s cn30xx; - struct cvmx_fpa_bist_status_s cn31xx; - struct cvmx_fpa_bist_status_s cn38xx; - struct cvmx_fpa_bist_status_s cn38xxp2; - struct cvmx_fpa_bist_status_s cn50xx; - struct cvmx_fpa_bist_status_s cn52xx; - struct cvmx_fpa_bist_status_s cn52xxp1; - struct cvmx_fpa_bist_status_s cn56xx; - struct cvmx_fpa_bist_status_s cn56xxp1; - struct cvmx_fpa_bist_status_s cn58xx; - struct cvmx_fpa_bist_status_s cn58xxp1; -}; - -union cvmx_fpa_ctl_status { - uint64_t u64; - struct cvmx_fpa_ctl_status_s { - uint64_t reserved_18_63:46; - uint64_t reset:1; - uint64_t use_ldt:1; - uint64_t use_stt:1; - uint64_t enb:1; - uint64_t mem1_err:7; - uint64_t mem0_err:7; - } s; - struct cvmx_fpa_ctl_status_s cn30xx; - struct cvmx_fpa_ctl_status_s cn31xx; - struct cvmx_fpa_ctl_status_s cn38xx; - struct cvmx_fpa_ctl_status_s cn38xxp2; - struct cvmx_fpa_ctl_status_s cn50xx; - struct cvmx_fpa_ctl_status_s cn52xx; - struct cvmx_fpa_ctl_status_s cn52xxp1; - struct cvmx_fpa_ctl_status_s cn56xx; - struct cvmx_fpa_ctl_status_s cn56xxp1; - struct cvmx_fpa_ctl_status_s cn58xx; - struct cvmx_fpa_ctl_status_s cn58xxp1; -}; - -union cvmx_fpa_fpfx_marks { - uint64_t u64; - struct cvmx_fpa_fpfx_marks_s { - uint64_t reserved_22_63:42; - uint64_t fpf_wr:11; - uint64_t fpf_rd:11; - } s; - struct cvmx_fpa_fpfx_marks_s cn38xx; - struct cvmx_fpa_fpfx_marks_s cn38xxp2; - struct cvmx_fpa_fpfx_marks_s cn56xx; - struct cvmx_fpa_fpfx_marks_s cn56xxp1; - struct cvmx_fpa_fpfx_marks_s cn58xx; - struct cvmx_fpa_fpfx_marks_s cn58xxp1; -}; - -union cvmx_fpa_fpfx_size { - uint64_t u64; - struct cvmx_fpa_fpfx_size_s { - uint64_t reserved_11_63:53; - uint64_t fpf_siz:11; - } s; - struct cvmx_fpa_fpfx_size_s cn38xx; - struct cvmx_fpa_fpfx_size_s cn38xxp2; - struct cvmx_fpa_fpfx_size_s cn56xx; - struct cvmx_fpa_fpfx_size_s cn56xxp1; - struct cvmx_fpa_fpfx_size_s cn58xx; - struct cvmx_fpa_fpfx_size_s cn58xxp1; -}; - -union cvmx_fpa_fpf0_marks { - uint64_t u64; - struct cvmx_fpa_fpf0_marks_s { - uint64_t reserved_24_63:40; - uint64_t fpf_wr:12; - uint64_t fpf_rd:12; - } s; - struct cvmx_fpa_fpf0_marks_s cn38xx; - struct cvmx_fpa_fpf0_marks_s cn38xxp2; - struct cvmx_fpa_fpf0_marks_s cn56xx; - struct cvmx_fpa_fpf0_marks_s cn56xxp1; - struct cvmx_fpa_fpf0_marks_s cn58xx; - struct cvmx_fpa_fpf0_marks_s cn58xxp1; -}; - -union cvmx_fpa_fpf0_size { - uint64_t u64; - struct cvmx_fpa_fpf0_size_s { - uint64_t reserved_12_63:52; - uint64_t fpf_siz:12; - } s; - struct cvmx_fpa_fpf0_size_s cn38xx; - struct cvmx_fpa_fpf0_size_s cn38xxp2; - struct cvmx_fpa_fpf0_size_s cn56xx; - struct cvmx_fpa_fpf0_size_s cn56xxp1; - struct cvmx_fpa_fpf0_size_s cn58xx; - struct cvmx_fpa_fpf0_size_s cn58xxp1; -}; - -union cvmx_fpa_int_enb { - uint64_t u64; - struct cvmx_fpa_int_enb_s { - uint64_t reserved_28_63:36; - uint64_t q7_perr:1; - uint64_t q7_coff:1; - uint64_t q7_und:1; - uint64_t q6_perr:1; - uint64_t q6_coff:1; - uint64_t q6_und:1; - uint64_t q5_perr:1; - uint64_t q5_coff:1; - uint64_t q5_und:1; - uint64_t q4_perr:1; - uint64_t q4_coff:1; - uint64_t q4_und:1; - uint64_t q3_perr:1; - uint64_t q3_coff:1; - uint64_t q3_und:1; - uint64_t q2_perr:1; - uint64_t q2_coff:1; - uint64_t q2_und:1; - uint64_t q1_perr:1; - uint64_t q1_coff:1; - uint64_t q1_und:1; - uint64_t q0_perr:1; - uint64_t q0_coff:1; - uint64_t q0_und:1; - uint64_t fed1_dbe:1; - uint64_t fed1_sbe:1; - uint64_t fed0_dbe:1; - uint64_t fed0_sbe:1; - } s; - struct cvmx_fpa_int_enb_s cn30xx; - struct cvmx_fpa_int_enb_s cn31xx; - struct cvmx_fpa_int_enb_s cn38xx; - struct cvmx_fpa_int_enb_s cn38xxp2; - struct cvmx_fpa_int_enb_s cn50xx; - struct cvmx_fpa_int_enb_s cn52xx; - struct cvmx_fpa_int_enb_s cn52xxp1; - struct cvmx_fpa_int_enb_s cn56xx; - struct cvmx_fpa_int_enb_s cn56xxp1; - struct cvmx_fpa_int_enb_s cn58xx; - struct cvmx_fpa_int_enb_s cn58xxp1; -}; - -union cvmx_fpa_int_sum { - uint64_t u64; - struct cvmx_fpa_int_sum_s { - uint64_t reserved_28_63:36; - uint64_t q7_perr:1; - uint64_t q7_coff:1; - uint64_t q7_und:1; - uint64_t q6_perr:1; - uint64_t q6_coff:1; - uint64_t q6_und:1; - uint64_t q5_perr:1; - uint64_t q5_coff:1; - uint64_t q5_und:1; - uint64_t q4_perr:1; - uint64_t q4_coff:1; - uint64_t q4_und:1; - uint64_t q3_perr:1; - uint64_t q3_coff:1; - uint64_t q3_und:1; - uint64_t q2_perr:1; - uint64_t q2_coff:1; - uint64_t q2_und:1; - uint64_t q1_perr:1; - uint64_t q1_coff:1; - uint64_t q1_und:1; - uint64_t q0_perr:1; - uint64_t q0_coff:1; - uint64_t q0_und:1; - uint64_t fed1_dbe:1; - uint64_t fed1_sbe:1; - uint64_t fed0_dbe:1; - uint64_t fed0_sbe:1; - } s; - struct cvmx_fpa_int_sum_s cn30xx; - struct cvmx_fpa_int_sum_s cn31xx; - struct cvmx_fpa_int_sum_s cn38xx; - struct cvmx_fpa_int_sum_s cn38xxp2; - struct cvmx_fpa_int_sum_s cn50xx; - struct cvmx_fpa_int_sum_s cn52xx; - struct cvmx_fpa_int_sum_s cn52xxp1; - struct cvmx_fpa_int_sum_s cn56xx; - struct cvmx_fpa_int_sum_s cn56xxp1; - struct cvmx_fpa_int_sum_s cn58xx; - struct cvmx_fpa_int_sum_s cn58xxp1; -}; - -union cvmx_fpa_quex_available { - uint64_t u64; - struct cvmx_fpa_quex_available_s { - uint64_t reserved_29_63:35; - uint64_t que_siz:29; - } s; - struct cvmx_fpa_quex_available_s cn30xx; - struct cvmx_fpa_quex_available_s cn31xx; - struct cvmx_fpa_quex_available_s cn38xx; - struct cvmx_fpa_quex_available_s cn38xxp2; - struct cvmx_fpa_quex_available_s cn50xx; - struct cvmx_fpa_quex_available_s cn52xx; - struct cvmx_fpa_quex_available_s cn52xxp1; - struct cvmx_fpa_quex_available_s cn56xx; - struct cvmx_fpa_quex_available_s cn56xxp1; - struct cvmx_fpa_quex_available_s cn58xx; - struct cvmx_fpa_quex_available_s cn58xxp1; -}; - -union cvmx_fpa_quex_page_index { - uint64_t u64; - struct cvmx_fpa_quex_page_index_s { - uint64_t reserved_25_63:39; - uint64_t pg_num:25; - } s; - struct cvmx_fpa_quex_page_index_s cn30xx; - struct cvmx_fpa_quex_page_index_s cn31xx; - struct cvmx_fpa_quex_page_index_s cn38xx; - struct cvmx_fpa_quex_page_index_s cn38xxp2; - struct cvmx_fpa_quex_page_index_s cn50xx; - struct cvmx_fpa_quex_page_index_s cn52xx; - struct cvmx_fpa_quex_page_index_s cn52xxp1; - struct cvmx_fpa_quex_page_index_s cn56xx; - struct cvmx_fpa_quex_page_index_s cn56xxp1; - struct cvmx_fpa_quex_page_index_s cn58xx; - struct cvmx_fpa_quex_page_index_s cn58xxp1; -}; - -union cvmx_fpa_que_act { - uint64_t u64; - struct cvmx_fpa_que_act_s { - uint64_t reserved_29_63:35; - uint64_t act_que:3; - uint64_t act_indx:26; - } s; - struct cvmx_fpa_que_act_s cn30xx; - struct cvmx_fpa_que_act_s cn31xx; - struct cvmx_fpa_que_act_s cn38xx; - struct cvmx_fpa_que_act_s cn38xxp2; - struct cvmx_fpa_que_act_s cn50xx; - struct cvmx_fpa_que_act_s cn52xx; - struct cvmx_fpa_que_act_s cn52xxp1; - struct cvmx_fpa_que_act_s cn56xx; - struct cvmx_fpa_que_act_s cn56xxp1; - struct cvmx_fpa_que_act_s cn58xx; - struct cvmx_fpa_que_act_s cn58xxp1; -}; - -union cvmx_fpa_que_exp { - uint64_t u64; - struct cvmx_fpa_que_exp_s { - uint64_t reserved_29_63:35; - uint64_t exp_que:3; - uint64_t exp_indx:26; - } s; - struct cvmx_fpa_que_exp_s cn30xx; - struct cvmx_fpa_que_exp_s cn31xx; - struct cvmx_fpa_que_exp_s cn38xx; - struct cvmx_fpa_que_exp_s cn38xxp2; - struct cvmx_fpa_que_exp_s cn50xx; - struct cvmx_fpa_que_exp_s cn52xx; - struct cvmx_fpa_que_exp_s cn52xxp1; - struct cvmx_fpa_que_exp_s cn56xx; - struct cvmx_fpa_que_exp_s cn56xxp1; - struct cvmx_fpa_que_exp_s cn58xx; - struct cvmx_fpa_que_exp_s cn58xxp1; -}; - -union cvmx_fpa_wart_ctl { - uint64_t u64; - struct cvmx_fpa_wart_ctl_s { - uint64_t reserved_16_63:48; - uint64_t ctl:16; - } s; - struct cvmx_fpa_wart_ctl_s cn30xx; - struct cvmx_fpa_wart_ctl_s cn31xx; - struct cvmx_fpa_wart_ctl_s cn38xx; - struct cvmx_fpa_wart_ctl_s cn38xxp2; - struct cvmx_fpa_wart_ctl_s cn50xx; - struct cvmx_fpa_wart_ctl_s cn52xx; - struct cvmx_fpa_wart_ctl_s cn52xxp1; - struct cvmx_fpa_wart_ctl_s cn56xx; - struct cvmx_fpa_wart_ctl_s cn56xxp1; - struct cvmx_fpa_wart_ctl_s cn58xx; - struct cvmx_fpa_wart_ctl_s cn58xxp1; -}; - -union cvmx_fpa_wart_status { - uint64_t u64; - struct cvmx_fpa_wart_status_s { - uint64_t reserved_32_63:32; - uint64_t status:32; - } s; - struct cvmx_fpa_wart_status_s cn30xx; - struct cvmx_fpa_wart_status_s cn31xx; - struct cvmx_fpa_wart_status_s cn38xx; - struct cvmx_fpa_wart_status_s cn38xxp2; - struct cvmx_fpa_wart_status_s cn50xx; - struct cvmx_fpa_wart_status_s cn52xx; - struct cvmx_fpa_wart_status_s cn52xxp1; - struct cvmx_fpa_wart_status_s cn56xx; - struct cvmx_fpa_wart_status_s cn56xxp1; - struct cvmx_fpa_wart_status_s cn58xx; - struct cvmx_fpa_wart_status_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-fpa.c b/drivers/staging/octeon/cvmx-fpa.c deleted file mode 100644 index ad44b8bd8057..000000000000 --- a/drivers/staging/octeon/cvmx-fpa.c +++ /dev/null @@ -1,183 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Support library for the hardware Free Pool Allocator. - * - * - */ - -#include "cvmx-config.h" -#include "cvmx.h" -#include "cvmx-fpa.h" -#include "cvmx-ipd.h" - -/** - * Current state of all the pools. Use access functions - * instead of using it directly. - */ -CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS]; - -/** - * Setup a FPA pool to control a new block of memory. The - * buffer pointer must be a physical address. - * - * @pool: Pool to initialize - * 0 <= pool < 8 - * @name: Constant character string to name this pool. - * String is not copied. - * @buffer: Pointer to the block of memory to use. This must be - * accessible by all processors and external hardware. - * @block_size: Size for each block controlled by the FPA - * @num_blocks: Number of blocks - * - * Returns 0 on Success, - * -1 on failure - */ -int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer, - uint64_t block_size, uint64_t num_blocks) -{ - char *ptr; - if (!buffer) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n"); - return -1; - } - if (pool >= CVMX_FPA_NUM_POOLS) { - cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n"); - return -1; - } - - if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n"); - return -1; - } - - if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) { - cvmx_dprintf - ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n"); - return -1; - } - - cvmx_fpa_pool_info[pool].name = name; - cvmx_fpa_pool_info[pool].size = block_size; - cvmx_fpa_pool_info[pool].starting_element_count = num_blocks; - cvmx_fpa_pool_info[pool].base = buffer; - - ptr = (char *)buffer; - while (num_blocks--) { - cvmx_fpa_free(ptr, pool, 0); - ptr += block_size; - } - return 0; -} - -/** - * Shutdown a Memory pool and validate that it had all of - * the buffers originally placed in it. - * - * @pool: Pool to shutdown - * Returns Zero on success - * - Positive is count of missing buffers - * - Negative is too many buffers or corrupted pointers - */ -uint64_t cvmx_fpa_shutdown_pool(uint64_t pool) -{ - uint64_t errors = 0; - uint64_t count = 0; - uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base); - uint64_t finish = - base + - cvmx_fpa_pool_info[pool].size * - cvmx_fpa_pool_info[pool].starting_element_count; - void *ptr; - uint64_t address; - - count = 0; - do { - ptr = cvmx_fpa_alloc(pool); - if (ptr) - address = cvmx_ptr_to_phys(ptr); - else - address = 0; - if (address) { - if ((address >= base) && (address < finish) && - (((address - - base) % cvmx_fpa_pool_info[pool].size) == 0)) { - count++; - } else { - cvmx_dprintf - ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n", - (unsigned long long)address, - cvmx_fpa_pool_info[pool].name, (int)pool); - errors++; - } - } - } while (address); - -#ifdef CVMX_ENABLE_PKO_FUNCTIONS - if (pool == 0) - cvmx_ipd_free_ptr(); -#endif - - if (errors) { - cvmx_dprintf - ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n", - cvmx_fpa_pool_info[pool].name, (int)pool, - (unsigned long long)base, (unsigned long long)finish, - (unsigned long long)cvmx_fpa_pool_info[pool].size); - return -errors; - } else - return 0; -} - -uint64_t cvmx_fpa_get_block_size(uint64_t pool) -{ - switch (pool) { - case 0: - return CVMX_FPA_POOL_0_SIZE; - case 1: - return CVMX_FPA_POOL_1_SIZE; - case 2: - return CVMX_FPA_POOL_2_SIZE; - case 3: - return CVMX_FPA_POOL_3_SIZE; - case 4: - return CVMX_FPA_POOL_4_SIZE; - case 5: - return CVMX_FPA_POOL_5_SIZE; - case 6: - return CVMX_FPA_POOL_6_SIZE; - case 7: - return CVMX_FPA_POOL_7_SIZE; - default: - return 0; - } -} diff --git a/drivers/staging/octeon/cvmx-fpa.h b/drivers/staging/octeon/cvmx-fpa.h deleted file mode 100644 index 1f04f9658736..000000000000 --- a/drivers/staging/octeon/cvmx-fpa.h +++ /dev/null @@ -1,299 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Interface to the hardware Free Pool Allocator. - * - * - */ - -#ifndef __CVMX_FPA_H__ -#define __CVMX_FPA_H__ - -#include "cvmx-address.h" -#include "cvmx-fpa-defs.h" - -#define CVMX_FPA_NUM_POOLS 8 -#define CVMX_FPA_MIN_BLOCK_SIZE 128 -#define CVMX_FPA_ALIGNMENT 128 - -/** - * Structure describing the data format used for stores to the FPA. - */ -typedef union { - uint64_t u64; - struct { - /* - * the (64-bit word) location in scratchpad to write - * to (if len != 0) - */ - uint64_t scraddr:8; - /* the number of words in the response (0 => no response) */ - uint64_t len:8; - /* the ID of the device on the non-coherent bus */ - uint64_t did:8; - /* - * the address that will appear in the first tick on - * the NCB bus. - */ - uint64_t addr:40; - } s; -} cvmx_fpa_iobdma_data_t; - -/** - * Structure describing the current state of a FPA pool. - */ -typedef struct { - /* Name it was created under */ - const char *name; - /* Size of each block */ - uint64_t size; - /* The base memory address of whole block */ - void *base; - /* The number of elements in the pool at creation */ - uint64_t starting_element_count; -} cvmx_fpa_pool_info_t; - -/** - * Current state of all the pools. Use access functions - * instead of using it directly. - */ -extern cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS]; - -/* CSR typedefs have been moved to cvmx-csr-*.h */ - -/** - * Return the name of the pool - * - * @pool: Pool to get the name of - * Returns The name - */ -static inline const char *cvmx_fpa_get_name(uint64_t pool) -{ - return cvmx_fpa_pool_info[pool].name; -} - -/** - * Return the base of the pool - * - * @pool: Pool to get the base of - * Returns The base - */ -static inline void *cvmx_fpa_get_base(uint64_t pool) -{ - return cvmx_fpa_pool_info[pool].base; -} - -/** - * Check if a pointer belongs to an FPA pool. Return non-zero - * if the supplied pointer is inside the memory controlled by - * an FPA pool. - * - * @pool: Pool to check - * @ptr: Pointer to check - * Returns Non-zero if pointer is in the pool. Zero if not - */ -static inline int cvmx_fpa_is_member(uint64_t pool, void *ptr) -{ - return ((ptr >= cvmx_fpa_pool_info[pool].base) && - ((char *)ptr < - ((char *)(cvmx_fpa_pool_info[pool].base)) + - cvmx_fpa_pool_info[pool].size * - cvmx_fpa_pool_info[pool].starting_element_count)); -} - -/** - * Enable the FPA for use. Must be performed after any CSR - * configuration but before any other FPA functions. - */ -static inline void cvmx_fpa_enable(void) -{ - union cvmx_fpa_ctl_status status; - - status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS); - if (status.s.enb) { - cvmx_dprintf - ("Warning: Enabling FPA when FPA already enabled.\n"); - } - - /* - * Do runtime check as we allow pass1 compiled code to run on - * pass2 chips. - */ - if (cvmx_octeon_is_pass1()) { - union cvmx_fpa_fpfx_marks marks; - int i; - for (i = 1; i < 8; i++) { - marks.u64 = - cvmx_read_csr(CVMX_FPA_FPF1_MARKS + (i - 1) * 8ull); - marks.s.fpf_wr = 0xe0; - cvmx_write_csr(CVMX_FPA_FPF1_MARKS + (i - 1) * 8ull, - marks.u64); - } - - /* Enforce a 10 cycle delay between config and enable */ - cvmx_wait(10); - } - - /* FIXME: CVMX_FPA_CTL_STATUS read is unmodelled */ - status.u64 = 0; - status.s.enb = 1; - cvmx_write_csr(CVMX_FPA_CTL_STATUS, status.u64); -} - -/** - * Get a new block from the FPA - * - * @pool: Pool to get the block from - * Returns Pointer to the block or NULL on failure - */ -static inline void *cvmx_fpa_alloc(uint64_t pool) -{ - uint64_t address = - cvmx_read_csr(CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool))); - if (address) - return cvmx_phys_to_ptr(address); - else - return NULL; -} - -/** - * Asynchronously get a new block from the FPA - * - * @scr_addr: Local scratch address to put response in. This is a byte address, - * but must be 8 byte aligned. - * @pool: Pool to get the block from - */ -static inline void cvmx_fpa_async_alloc(uint64_t scr_addr, uint64_t pool) -{ - cvmx_fpa_iobdma_data_t data; - - /* - * Hardware only uses 64 bit aligned locations, so convert - * from byte address to 64-bit index - */ - data.s.scraddr = scr_addr >> 3; - data.s.len = 1; - data.s.did = CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool); - data.s.addr = 0; - cvmx_send_single(data.u64); -} - -/** - * Free a block allocated with a FPA pool. Does NOT provide memory - * ordering in cases where the memory block was modified by the core. - * - * @ptr: Block to free - * @pool: Pool to put it in - * @num_cache_lines: - * Cache lines to invalidate - */ -static inline void cvmx_fpa_free_nosync(void *ptr, uint64_t pool, - uint64_t num_cache_lines) -{ - cvmx_addr_t newptr; - newptr.u64 = cvmx_ptr_to_phys(ptr); - newptr.sfilldidspace.didspace = - CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); - /* Prevent GCC from reordering around free */ - barrier(); - /* value written is number of cache lines not written back */ - cvmx_write_io(newptr.u64, num_cache_lines); -} - -/** - * Free a block allocated with a FPA pool. Provides required memory - * ordering in cases where memory block was modified by core. - * - * @ptr: Block to free - * @pool: Pool to put it in - * @num_cache_lines: - * Cache lines to invalidate - */ -static inline void cvmx_fpa_free(void *ptr, uint64_t pool, - uint64_t num_cache_lines) -{ - cvmx_addr_t newptr; - newptr.u64 = cvmx_ptr_to_phys(ptr); - newptr.sfilldidspace.didspace = - CVMX_ADDR_DIDSPACE(CVMX_FULL_DID(CVMX_OCT_DID_FPA, pool)); - /* - * Make sure that any previous writes to memory go out before - * we free this buffer. This also serves as a barrier to - * prevent GCC from reordering operations to after the - * free. - */ - CVMX_SYNCWS; - /* value written is number of cache lines not written back */ - cvmx_write_io(newptr.u64, num_cache_lines); -} - -/** - * Setup a FPA pool to control a new block of memory. - * This can only be called once per pool. Make sure proper - * locking enforces this. - * - * @pool: Pool to initialize - * 0 <= pool < 8 - * @name: Constant character string to name this pool. - * String is not copied. - * @buffer: Pointer to the block of memory to use. This must be - * accessible by all processors and external hardware. - * @block_size: Size for each block controlled by the FPA - * @num_blocks: Number of blocks - * - * Returns 0 on Success, - * -1 on failure - */ -extern int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer, - uint64_t block_size, uint64_t num_blocks); - -/** - * Shutdown a Memory pool and validate that it had all of - * the buffers originally placed in it. This should only be - * called by one processor after all hardware has finished - * using the pool. - * - * @pool: Pool to shutdown - * Returns Zero on success - * - Positive is count of missing buffers - * - Negative is too many buffers or corrupted pointers - */ -extern uint64_t cvmx_fpa_shutdown_pool(uint64_t pool); - -/** - * Get the size of blocks controlled by the pool - * This is resolved to a constant at compile time. - * - * @pool: Pool to access - * Returns Size of the block in bytes - */ -uint64_t cvmx_fpa_get_block_size(uint64_t pool); - -#endif /* __CVM_FPA_H__ */ diff --git a/drivers/staging/octeon/cvmx-gmxx-defs.h b/drivers/staging/octeon/cvmx-gmxx-defs.h deleted file mode 100644 index 946a43a73fd7..000000000000 --- a/drivers/staging/octeon/cvmx-gmxx-defs.h +++ /dev/null @@ -1,2529 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_GMXX_DEFS_H__ -#define __CVMX_GMXX_DEFS_H__ - -#define CVMX_GMXX_BAD_REG(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000518ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_BIST(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000400ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_CLK_EN(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080007F0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_HG2_CONTROL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000550ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_INF_MODE(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080007F8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_NXA_ADR(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000510ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_PRTX_CBFC_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000580ull + (((offset) & 0) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_PRTX_CFG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000010ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM0(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000180ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM1(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000188ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM2(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000190ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM3(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000198ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM4(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080001A0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM5(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080001A8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CAM_EN(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000108ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_ADR_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000100ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_DECISION(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000040ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_FRM_CHK(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000020ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_FRM_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000018ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_FRM_MAX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000030ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_FRM_MIN(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000028ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_IFG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000058ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_INT_EN(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000008ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_INT_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000000ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_JABBER(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000038ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_PAUSE_DROP_TIME(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000068ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_RX_INBND(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000060ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000050ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_OCTS(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000088ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_OCTS_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000098ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_OCTS_DMAC(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080000A8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_OCTS_DRP(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080000B8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_PKTS(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000080ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_PKTS_BAD(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080000C0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_PKTS_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000090ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_PKTS_DMAC(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080000A0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_STATS_PKTS_DRP(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080000B0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RXX_UDD_SKP(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000048ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_BP_DROPX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000420ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_BP_OFFX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000460ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_BP_ONX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000440ull + (((offset) & 3) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_HG2_STATUS(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000548ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_PASS_EN(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080005F8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_PASS_MAPX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000600ull + (((offset) & 15) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_PRTS(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000410ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_PRT_INFO(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004E8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_TX_STATUS(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080007E8ull + (((block_id) & 0) * 0x8000000ull)) -#define CVMX_GMXX_RX_XAUI_BAD_COL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000538ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_RX_XAUI_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000530ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_SMACX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000230ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_STAT_BP(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000520ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_APPEND(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000218ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_BURST(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000228ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_CBFC_XOFF(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080005A0ull + (((offset) & 0) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_CBFC_XON(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080005C0ull + (((offset) & 0) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_CLK(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000208ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000270ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_MIN_PKT(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000240ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000248ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_PAUSE_PKT_TIME(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000238ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_PAUSE_TOGO(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000258ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_PAUSE_ZERO(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000260ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_SGMII_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000300ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_SLOT(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000220ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_SOFT_PAUSE(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000250ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT0(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000280ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT1(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000288ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT2(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000290ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT3(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000298ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT4(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080002A0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT5(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080002A8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT6(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080002B0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT7(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080002B8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT8(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080002C0ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STAT9(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800080002C8ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_STATS_CTL(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000268ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TXX_THRESH(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000210ull + (((offset) & 3) * 2048) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_BP(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004D0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_CLK_MSKX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000780ull + (((offset) & 1) * 8) + (((block_id) & 0) * 0x0ull)) -#define CVMX_GMXX_TX_COL_ATTEMPT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000498ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_CORRUPT(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004D8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_HG2_REG1(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000558ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_HG2_REG2(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000560ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_IFG(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000488ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_INT_EN(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000508ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_INT_REG(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000500ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_JAM(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000490ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_LFSR(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004F8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_OVR_BP(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004C8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_PAUSE_PKT_DMAC(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004A0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_PAUSE_PKT_TYPE(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004A8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_PRTS(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000480ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_SPI_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004C0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_SPI_DRAIN(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004E0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_SPI_MAX(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004B0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_SPI_ROUNDX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000680ull + (((offset) & 31) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_SPI_THRESH(block_id) \ - CVMX_ADD_IO_SEG(0x00011800080004B8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_TX_XAUI_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000528ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_GMXX_XAUI_EXT_LOOPBACK(block_id) \ - CVMX_ADD_IO_SEG(0x0001180008000540ull + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_gmxx_bad_reg { - uint64_t u64; - struct cvmx_gmxx_bad_reg_s { - uint64_t reserved_31_63:33; - uint64_t inb_nxa:4; - uint64_t statovr:1; - uint64_t loststat:4; - uint64_t reserved_18_21:4; - uint64_t out_ovr:16; - uint64_t ncb_ovr:1; - uint64_t out_col:1; - } s; - struct cvmx_gmxx_bad_reg_cn30xx { - uint64_t reserved_31_63:33; - uint64_t inb_nxa:4; - uint64_t statovr:1; - uint64_t reserved_25_25:1; - uint64_t loststat:3; - uint64_t reserved_5_21:17; - uint64_t out_ovr:3; - uint64_t reserved_0_1:2; - } cn30xx; - struct cvmx_gmxx_bad_reg_cn30xx cn31xx; - struct cvmx_gmxx_bad_reg_s cn38xx; - struct cvmx_gmxx_bad_reg_s cn38xxp2; - struct cvmx_gmxx_bad_reg_cn30xx cn50xx; - struct cvmx_gmxx_bad_reg_cn52xx { - uint64_t reserved_31_63:33; - uint64_t inb_nxa:4; - uint64_t statovr:1; - uint64_t loststat:4; - uint64_t reserved_6_21:16; - uint64_t out_ovr:4; - uint64_t reserved_0_1:2; - } cn52xx; - struct cvmx_gmxx_bad_reg_cn52xx cn52xxp1; - struct cvmx_gmxx_bad_reg_cn52xx cn56xx; - struct cvmx_gmxx_bad_reg_cn52xx cn56xxp1; - struct cvmx_gmxx_bad_reg_s cn58xx; - struct cvmx_gmxx_bad_reg_s cn58xxp1; -}; - -union cvmx_gmxx_bist { - uint64_t u64; - struct cvmx_gmxx_bist_s { - uint64_t reserved_17_63:47; - uint64_t status:17; - } s; - struct cvmx_gmxx_bist_cn30xx { - uint64_t reserved_10_63:54; - uint64_t status:10; - } cn30xx; - struct cvmx_gmxx_bist_cn30xx cn31xx; - struct cvmx_gmxx_bist_cn30xx cn38xx; - struct cvmx_gmxx_bist_cn30xx cn38xxp2; - struct cvmx_gmxx_bist_cn50xx { - uint64_t reserved_12_63:52; - uint64_t status:12; - } cn50xx; - struct cvmx_gmxx_bist_cn52xx { - uint64_t reserved_16_63:48; - uint64_t status:16; - } cn52xx; - struct cvmx_gmxx_bist_cn52xx cn52xxp1; - struct cvmx_gmxx_bist_cn52xx cn56xx; - struct cvmx_gmxx_bist_cn52xx cn56xxp1; - struct cvmx_gmxx_bist_s cn58xx; - struct cvmx_gmxx_bist_s cn58xxp1; -}; - -union cvmx_gmxx_clk_en { - uint64_t u64; - struct cvmx_gmxx_clk_en_s { - uint64_t reserved_1_63:63; - uint64_t clk_en:1; - } s; - struct cvmx_gmxx_clk_en_s cn52xx; - struct cvmx_gmxx_clk_en_s cn52xxp1; - struct cvmx_gmxx_clk_en_s cn56xx; - struct cvmx_gmxx_clk_en_s cn56xxp1; -}; - -union cvmx_gmxx_hg2_control { - uint64_t u64; - struct cvmx_gmxx_hg2_control_s { - uint64_t reserved_19_63:45; - uint64_t hg2tx_en:1; - uint64_t hg2rx_en:1; - uint64_t phys_en:1; - uint64_t logl_en:16; - } s; - struct cvmx_gmxx_hg2_control_s cn52xx; - struct cvmx_gmxx_hg2_control_s cn52xxp1; - struct cvmx_gmxx_hg2_control_s cn56xx; -}; - -union cvmx_gmxx_inf_mode { - uint64_t u64; - struct cvmx_gmxx_inf_mode_s { - uint64_t reserved_10_63:54; - uint64_t speed:2; - uint64_t reserved_6_7:2; - uint64_t mode:2; - uint64_t reserved_3_3:1; - uint64_t p0mii:1; - uint64_t en:1; - uint64_t type:1; - } s; - struct cvmx_gmxx_inf_mode_cn30xx { - uint64_t reserved_3_63:61; - uint64_t p0mii:1; - uint64_t en:1; - uint64_t type:1; - } cn30xx; - struct cvmx_gmxx_inf_mode_cn31xx { - uint64_t reserved_2_63:62; - uint64_t en:1; - uint64_t type:1; - } cn31xx; - struct cvmx_gmxx_inf_mode_cn31xx cn38xx; - struct cvmx_gmxx_inf_mode_cn31xx cn38xxp2; - struct cvmx_gmxx_inf_mode_cn30xx cn50xx; - struct cvmx_gmxx_inf_mode_cn52xx { - uint64_t reserved_10_63:54; - uint64_t speed:2; - uint64_t reserved_6_7:2; - uint64_t mode:2; - uint64_t reserved_2_3:2; - uint64_t en:1; - uint64_t type:1; - } cn52xx; - struct cvmx_gmxx_inf_mode_cn52xx cn52xxp1; - struct cvmx_gmxx_inf_mode_cn52xx cn56xx; - struct cvmx_gmxx_inf_mode_cn52xx cn56xxp1; - struct cvmx_gmxx_inf_mode_cn31xx cn58xx; - struct cvmx_gmxx_inf_mode_cn31xx cn58xxp1; -}; - -union cvmx_gmxx_nxa_adr { - uint64_t u64; - struct cvmx_gmxx_nxa_adr_s { - uint64_t reserved_6_63:58; - uint64_t prt:6; - } s; - struct cvmx_gmxx_nxa_adr_s cn30xx; - struct cvmx_gmxx_nxa_adr_s cn31xx; - struct cvmx_gmxx_nxa_adr_s cn38xx; - struct cvmx_gmxx_nxa_adr_s cn38xxp2; - struct cvmx_gmxx_nxa_adr_s cn50xx; - struct cvmx_gmxx_nxa_adr_s cn52xx; - struct cvmx_gmxx_nxa_adr_s cn52xxp1; - struct cvmx_gmxx_nxa_adr_s cn56xx; - struct cvmx_gmxx_nxa_adr_s cn56xxp1; - struct cvmx_gmxx_nxa_adr_s cn58xx; - struct cvmx_gmxx_nxa_adr_s cn58xxp1; -}; - -union cvmx_gmxx_prtx_cbfc_ctl { - uint64_t u64; - struct cvmx_gmxx_prtx_cbfc_ctl_s { - uint64_t phys_en:16; - uint64_t logl_en:16; - uint64_t phys_bp:16; - uint64_t reserved_4_15:12; - uint64_t bck_en:1; - uint64_t drp_en:1; - uint64_t tx_en:1; - uint64_t rx_en:1; - } s; - struct cvmx_gmxx_prtx_cbfc_ctl_s cn52xx; - struct cvmx_gmxx_prtx_cbfc_ctl_s cn56xx; -}; - -union cvmx_gmxx_prtx_cfg { - uint64_t u64; - struct cvmx_gmxx_prtx_cfg_s { - uint64_t reserved_14_63:50; - uint64_t tx_idle:1; - uint64_t rx_idle:1; - uint64_t reserved_9_11:3; - uint64_t speed_msb:1; - uint64_t reserved_4_7:4; - uint64_t slottime:1; - uint64_t duplex:1; - uint64_t speed:1; - uint64_t en:1; - } s; - struct cvmx_gmxx_prtx_cfg_cn30xx { - uint64_t reserved_4_63:60; - uint64_t slottime:1; - uint64_t duplex:1; - uint64_t speed:1; - uint64_t en:1; - } cn30xx; - struct cvmx_gmxx_prtx_cfg_cn30xx cn31xx; - struct cvmx_gmxx_prtx_cfg_cn30xx cn38xx; - struct cvmx_gmxx_prtx_cfg_cn30xx cn38xxp2; - struct cvmx_gmxx_prtx_cfg_cn30xx cn50xx; - struct cvmx_gmxx_prtx_cfg_s cn52xx; - struct cvmx_gmxx_prtx_cfg_s cn52xxp1; - struct cvmx_gmxx_prtx_cfg_s cn56xx; - struct cvmx_gmxx_prtx_cfg_s cn56xxp1; - struct cvmx_gmxx_prtx_cfg_cn30xx cn58xx; - struct cvmx_gmxx_prtx_cfg_cn30xx cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam0 { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam0_s { - uint64_t adr:64; - } s; - struct cvmx_gmxx_rxx_adr_cam0_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam0_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam0_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam0_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam0_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam1 { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam1_s { - uint64_t adr:64; - } s; - struct cvmx_gmxx_rxx_adr_cam1_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam1_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam1_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam1_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam1_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam2 { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam2_s { - uint64_t adr:64; - } s; - struct cvmx_gmxx_rxx_adr_cam2_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam2_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam2_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam2_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam2_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam3 { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam3_s { - uint64_t adr:64; - } s; - struct cvmx_gmxx_rxx_adr_cam3_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam3_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam3_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam3_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam3_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam4 { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam4_s { - uint64_t adr:64; - } s; - struct cvmx_gmxx_rxx_adr_cam4_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam4_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam4_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam4_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam4_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam5 { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam5_s { - uint64_t adr:64; - } s; - struct cvmx_gmxx_rxx_adr_cam5_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam5_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam5_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam5_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam5_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_cam_en { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_cam_en_s { - uint64_t reserved_8_63:56; - uint64_t en:8; - } s; - struct cvmx_gmxx_rxx_adr_cam_en_s cn30xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn31xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn38xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_cam_en_s cn50xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn52xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_cam_en_s cn56xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_cam_en_s cn58xx; - struct cvmx_gmxx_rxx_adr_cam_en_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_adr_ctl { - uint64_t u64; - struct cvmx_gmxx_rxx_adr_ctl_s { - uint64_t reserved_4_63:60; - uint64_t cam_mode:1; - uint64_t mcst:2; - uint64_t bcst:1; - } s; - struct cvmx_gmxx_rxx_adr_ctl_s cn30xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn31xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn38xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn38xxp2; - struct cvmx_gmxx_rxx_adr_ctl_s cn50xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn52xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn52xxp1; - struct cvmx_gmxx_rxx_adr_ctl_s cn56xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn56xxp1; - struct cvmx_gmxx_rxx_adr_ctl_s cn58xx; - struct cvmx_gmxx_rxx_adr_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_decision { - uint64_t u64; - struct cvmx_gmxx_rxx_decision_s { - uint64_t reserved_5_63:59; - uint64_t cnt:5; - } s; - struct cvmx_gmxx_rxx_decision_s cn30xx; - struct cvmx_gmxx_rxx_decision_s cn31xx; - struct cvmx_gmxx_rxx_decision_s cn38xx; - struct cvmx_gmxx_rxx_decision_s cn38xxp2; - struct cvmx_gmxx_rxx_decision_s cn50xx; - struct cvmx_gmxx_rxx_decision_s cn52xx; - struct cvmx_gmxx_rxx_decision_s cn52xxp1; - struct cvmx_gmxx_rxx_decision_s cn56xx; - struct cvmx_gmxx_rxx_decision_s cn56xxp1; - struct cvmx_gmxx_rxx_decision_s cn58xx; - struct cvmx_gmxx_rxx_decision_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_frm_chk { - uint64_t u64; - struct cvmx_gmxx_rxx_frm_chk_s { - uint64_t reserved_10_63:54; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } s; - struct cvmx_gmxx_rxx_frm_chk_s cn30xx; - struct cvmx_gmxx_rxx_frm_chk_s cn31xx; - struct cvmx_gmxx_rxx_frm_chk_s cn38xx; - struct cvmx_gmxx_rxx_frm_chk_s cn38xxp2; - struct cvmx_gmxx_rxx_frm_chk_cn50xx { - uint64_t reserved_10_63:54; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_6_6:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn50xx; - struct cvmx_gmxx_rxx_frm_chk_cn52xx { - uint64_t reserved_9_63:55; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_5_6:2; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn52xx; - struct cvmx_gmxx_rxx_frm_chk_cn52xx cn52xxp1; - struct cvmx_gmxx_rxx_frm_chk_cn52xx cn56xx; - struct cvmx_gmxx_rxx_frm_chk_cn52xx cn56xxp1; - struct cvmx_gmxx_rxx_frm_chk_s cn58xx; - struct cvmx_gmxx_rxx_frm_chk_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_frm_ctl { - uint64_t u64; - struct cvmx_gmxx_rxx_frm_ctl_s { - uint64_t reserved_11_63:53; - uint64_t null_dis:1; - uint64_t pre_align:1; - uint64_t pad_len:1; - uint64_t vlan_len:1; - uint64_t pre_free:1; - uint64_t ctl_smac:1; - uint64_t ctl_mcst:1; - uint64_t ctl_bck:1; - uint64_t ctl_drp:1; - uint64_t pre_strp:1; - uint64_t pre_chk:1; - } s; - struct cvmx_gmxx_rxx_frm_ctl_cn30xx { - uint64_t reserved_9_63:55; - uint64_t pad_len:1; - uint64_t vlan_len:1; - uint64_t pre_free:1; - uint64_t ctl_smac:1; - uint64_t ctl_mcst:1; - uint64_t ctl_bck:1; - uint64_t ctl_drp:1; - uint64_t pre_strp:1; - uint64_t pre_chk:1; - } cn30xx; - struct cvmx_gmxx_rxx_frm_ctl_cn31xx { - uint64_t reserved_8_63:56; - uint64_t vlan_len:1; - uint64_t pre_free:1; - uint64_t ctl_smac:1; - uint64_t ctl_mcst:1; - uint64_t ctl_bck:1; - uint64_t ctl_drp:1; - uint64_t pre_strp:1; - uint64_t pre_chk:1; - } cn31xx; - struct cvmx_gmxx_rxx_frm_ctl_cn30xx cn38xx; - struct cvmx_gmxx_rxx_frm_ctl_cn31xx cn38xxp2; - struct cvmx_gmxx_rxx_frm_ctl_cn50xx { - uint64_t reserved_11_63:53; - uint64_t null_dis:1; - uint64_t pre_align:1; - uint64_t reserved_7_8:2; - uint64_t pre_free:1; - uint64_t ctl_smac:1; - uint64_t ctl_mcst:1; - uint64_t ctl_bck:1; - uint64_t ctl_drp:1; - uint64_t pre_strp:1; - uint64_t pre_chk:1; - } cn50xx; - struct cvmx_gmxx_rxx_frm_ctl_cn50xx cn52xx; - struct cvmx_gmxx_rxx_frm_ctl_cn50xx cn52xxp1; - struct cvmx_gmxx_rxx_frm_ctl_cn50xx cn56xx; - struct cvmx_gmxx_rxx_frm_ctl_cn56xxp1 { - uint64_t reserved_10_63:54; - uint64_t pre_align:1; - uint64_t reserved_7_8:2; - uint64_t pre_free:1; - uint64_t ctl_smac:1; - uint64_t ctl_mcst:1; - uint64_t ctl_bck:1; - uint64_t ctl_drp:1; - uint64_t pre_strp:1; - uint64_t pre_chk:1; - } cn56xxp1; - struct cvmx_gmxx_rxx_frm_ctl_s cn58xx; - struct cvmx_gmxx_rxx_frm_ctl_cn30xx cn58xxp1; -}; - -union cvmx_gmxx_rxx_frm_max { - uint64_t u64; - struct cvmx_gmxx_rxx_frm_max_s { - uint64_t reserved_16_63:48; - uint64_t len:16; - } s; - struct cvmx_gmxx_rxx_frm_max_s cn30xx; - struct cvmx_gmxx_rxx_frm_max_s cn31xx; - struct cvmx_gmxx_rxx_frm_max_s cn38xx; - struct cvmx_gmxx_rxx_frm_max_s cn38xxp2; - struct cvmx_gmxx_rxx_frm_max_s cn58xx; - struct cvmx_gmxx_rxx_frm_max_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_frm_min { - uint64_t u64; - struct cvmx_gmxx_rxx_frm_min_s { - uint64_t reserved_16_63:48; - uint64_t len:16; - } s; - struct cvmx_gmxx_rxx_frm_min_s cn30xx; - struct cvmx_gmxx_rxx_frm_min_s cn31xx; - struct cvmx_gmxx_rxx_frm_min_s cn38xx; - struct cvmx_gmxx_rxx_frm_min_s cn38xxp2; - struct cvmx_gmxx_rxx_frm_min_s cn58xx; - struct cvmx_gmxx_rxx_frm_min_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_ifg { - uint64_t u64; - struct cvmx_gmxx_rxx_ifg_s { - uint64_t reserved_4_63:60; - uint64_t ifg:4; - } s; - struct cvmx_gmxx_rxx_ifg_s cn30xx; - struct cvmx_gmxx_rxx_ifg_s cn31xx; - struct cvmx_gmxx_rxx_ifg_s cn38xx; - struct cvmx_gmxx_rxx_ifg_s cn38xxp2; - struct cvmx_gmxx_rxx_ifg_s cn50xx; - struct cvmx_gmxx_rxx_ifg_s cn52xx; - struct cvmx_gmxx_rxx_ifg_s cn52xxp1; - struct cvmx_gmxx_rxx_ifg_s cn56xx; - struct cvmx_gmxx_rxx_ifg_s cn56xxp1; - struct cvmx_gmxx_rxx_ifg_s cn58xx; - struct cvmx_gmxx_rxx_ifg_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_int_en { - uint64_t u64; - struct cvmx_gmxx_rxx_int_en_s { - uint64_t reserved_29_63:35; - uint64_t hg2cc:1; - uint64_t hg2fld:1; - uint64_t undat:1; - uint64_t uneop:1; - uint64_t unsop:1; - uint64_t bad_term:1; - uint64_t bad_seq:1; - uint64_t rem_fault:1; - uint64_t loc_fault:1; - uint64_t pause_drp:1; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } s; - struct cvmx_gmxx_rxx_int_en_cn30xx { - uint64_t reserved_19_63:45; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } cn30xx; - struct cvmx_gmxx_rxx_int_en_cn30xx cn31xx; - struct cvmx_gmxx_rxx_int_en_cn30xx cn38xx; - struct cvmx_gmxx_rxx_int_en_cn30xx cn38xxp2; - struct cvmx_gmxx_rxx_int_en_cn50xx { - uint64_t reserved_20_63:44; - uint64_t pause_drp:1; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_6_6:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn50xx; - struct cvmx_gmxx_rxx_int_en_cn52xx { - uint64_t reserved_29_63:35; - uint64_t hg2cc:1; - uint64_t hg2fld:1; - uint64_t undat:1; - uint64_t uneop:1; - uint64_t unsop:1; - uint64_t bad_term:1; - uint64_t bad_seq:1; - uint64_t rem_fault:1; - uint64_t loc_fault:1; - uint64_t pause_drp:1; - uint64_t reserved_16_18:3; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t reserved_9_9:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_5_6:2; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn52xx; - struct cvmx_gmxx_rxx_int_en_cn52xx cn52xxp1; - struct cvmx_gmxx_rxx_int_en_cn52xx cn56xx; - struct cvmx_gmxx_rxx_int_en_cn56xxp1 { - uint64_t reserved_27_63:37; - uint64_t undat:1; - uint64_t uneop:1; - uint64_t unsop:1; - uint64_t bad_term:1; - uint64_t bad_seq:1; - uint64_t rem_fault:1; - uint64_t loc_fault:1; - uint64_t pause_drp:1; - uint64_t reserved_16_18:3; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t reserved_9_9:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_5_6:2; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn56xxp1; - struct cvmx_gmxx_rxx_int_en_cn58xx { - uint64_t reserved_20_63:44; - uint64_t pause_drp:1; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } cn58xx; - struct cvmx_gmxx_rxx_int_en_cn58xx cn58xxp1; -}; - -union cvmx_gmxx_rxx_int_reg { - uint64_t u64; - struct cvmx_gmxx_rxx_int_reg_s { - uint64_t reserved_29_63:35; - uint64_t hg2cc:1; - uint64_t hg2fld:1; - uint64_t undat:1; - uint64_t uneop:1; - uint64_t unsop:1; - uint64_t bad_term:1; - uint64_t bad_seq:1; - uint64_t rem_fault:1; - uint64_t loc_fault:1; - uint64_t pause_drp:1; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } s; - struct cvmx_gmxx_rxx_int_reg_cn30xx { - uint64_t reserved_19_63:45; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } cn30xx; - struct cvmx_gmxx_rxx_int_reg_cn30xx cn31xx; - struct cvmx_gmxx_rxx_int_reg_cn30xx cn38xx; - struct cvmx_gmxx_rxx_int_reg_cn30xx cn38xxp2; - struct cvmx_gmxx_rxx_int_reg_cn50xx { - uint64_t reserved_20_63:44; - uint64_t pause_drp:1; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_6_6:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn50xx; - struct cvmx_gmxx_rxx_int_reg_cn52xx { - uint64_t reserved_29_63:35; - uint64_t hg2cc:1; - uint64_t hg2fld:1; - uint64_t undat:1; - uint64_t uneop:1; - uint64_t unsop:1; - uint64_t bad_term:1; - uint64_t bad_seq:1; - uint64_t rem_fault:1; - uint64_t loc_fault:1; - uint64_t pause_drp:1; - uint64_t reserved_16_18:3; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t reserved_9_9:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_5_6:2; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn52xx; - struct cvmx_gmxx_rxx_int_reg_cn52xx cn52xxp1; - struct cvmx_gmxx_rxx_int_reg_cn52xx cn56xx; - struct cvmx_gmxx_rxx_int_reg_cn56xxp1 { - uint64_t reserved_27_63:37; - uint64_t undat:1; - uint64_t uneop:1; - uint64_t unsop:1; - uint64_t bad_term:1; - uint64_t bad_seq:1; - uint64_t rem_fault:1; - uint64_t loc_fault:1; - uint64_t pause_drp:1; - uint64_t reserved_16_18:3; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t reserved_9_9:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t reserved_5_6:2; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t reserved_2_2:1; - uint64_t carext:1; - uint64_t reserved_0_0:1; - } cn56xxp1; - struct cvmx_gmxx_rxx_int_reg_cn58xx { - uint64_t reserved_20_63:44; - uint64_t pause_drp:1; - uint64_t phy_dupx:1; - uint64_t phy_spd:1; - uint64_t phy_link:1; - uint64_t ifgerr:1; - uint64_t coldet:1; - uint64_t falerr:1; - uint64_t rsverr:1; - uint64_t pcterr:1; - uint64_t ovrerr:1; - uint64_t niberr:1; - uint64_t skperr:1; - uint64_t rcverr:1; - uint64_t lenerr:1; - uint64_t alnerr:1; - uint64_t fcserr:1; - uint64_t jabber:1; - uint64_t maxerr:1; - uint64_t carext:1; - uint64_t minerr:1; - } cn58xx; - struct cvmx_gmxx_rxx_int_reg_cn58xx cn58xxp1; -}; - -union cvmx_gmxx_rxx_jabber { - uint64_t u64; - struct cvmx_gmxx_rxx_jabber_s { - uint64_t reserved_16_63:48; - uint64_t cnt:16; - } s; - struct cvmx_gmxx_rxx_jabber_s cn30xx; - struct cvmx_gmxx_rxx_jabber_s cn31xx; - struct cvmx_gmxx_rxx_jabber_s cn38xx; - struct cvmx_gmxx_rxx_jabber_s cn38xxp2; - struct cvmx_gmxx_rxx_jabber_s cn50xx; - struct cvmx_gmxx_rxx_jabber_s cn52xx; - struct cvmx_gmxx_rxx_jabber_s cn52xxp1; - struct cvmx_gmxx_rxx_jabber_s cn56xx; - struct cvmx_gmxx_rxx_jabber_s cn56xxp1; - struct cvmx_gmxx_rxx_jabber_s cn58xx; - struct cvmx_gmxx_rxx_jabber_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_pause_drop_time { - uint64_t u64; - struct cvmx_gmxx_rxx_pause_drop_time_s { - uint64_t reserved_16_63:48; - uint64_t status:16; - } s; - struct cvmx_gmxx_rxx_pause_drop_time_s cn50xx; - struct cvmx_gmxx_rxx_pause_drop_time_s cn52xx; - struct cvmx_gmxx_rxx_pause_drop_time_s cn52xxp1; - struct cvmx_gmxx_rxx_pause_drop_time_s cn56xx; - struct cvmx_gmxx_rxx_pause_drop_time_s cn56xxp1; - struct cvmx_gmxx_rxx_pause_drop_time_s cn58xx; - struct cvmx_gmxx_rxx_pause_drop_time_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_rx_inbnd { - uint64_t u64; - struct cvmx_gmxx_rxx_rx_inbnd_s { - uint64_t reserved_4_63:60; - uint64_t duplex:1; - uint64_t speed:2; - uint64_t status:1; - } s; - struct cvmx_gmxx_rxx_rx_inbnd_s cn30xx; - struct cvmx_gmxx_rxx_rx_inbnd_s cn31xx; - struct cvmx_gmxx_rxx_rx_inbnd_s cn38xx; - struct cvmx_gmxx_rxx_rx_inbnd_s cn38xxp2; - struct cvmx_gmxx_rxx_rx_inbnd_s cn50xx; - struct cvmx_gmxx_rxx_rx_inbnd_s cn58xx; - struct cvmx_gmxx_rxx_rx_inbnd_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_ctl { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_ctl_s { - uint64_t reserved_1_63:63; - uint64_t rd_clr:1; - } s; - struct cvmx_gmxx_rxx_stats_ctl_s cn30xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn31xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn38xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_ctl_s cn50xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn52xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_ctl_s cn56xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_ctl_s cn58xx; - struct cvmx_gmxx_rxx_stats_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_octs { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_octs_s { - uint64_t reserved_48_63:16; - uint64_t cnt:48; - } s; - struct cvmx_gmxx_rxx_stats_octs_s cn30xx; - struct cvmx_gmxx_rxx_stats_octs_s cn31xx; - struct cvmx_gmxx_rxx_stats_octs_s cn38xx; - struct cvmx_gmxx_rxx_stats_octs_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_octs_s cn50xx; - struct cvmx_gmxx_rxx_stats_octs_s cn52xx; - struct cvmx_gmxx_rxx_stats_octs_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_octs_s cn56xx; - struct cvmx_gmxx_rxx_stats_octs_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_octs_s cn58xx; - struct cvmx_gmxx_rxx_stats_octs_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_octs_ctl { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_octs_ctl_s { - uint64_t reserved_48_63:16; - uint64_t cnt:48; - } s; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn30xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn31xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn38xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn50xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn52xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn56xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn58xx; - struct cvmx_gmxx_rxx_stats_octs_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_octs_dmac { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_octs_dmac_s { - uint64_t reserved_48_63:16; - uint64_t cnt:48; - } s; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn30xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn31xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn38xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn50xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn52xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn56xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn58xx; - struct cvmx_gmxx_rxx_stats_octs_dmac_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_octs_drp { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_octs_drp_s { - uint64_t reserved_48_63:16; - uint64_t cnt:48; - } s; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn30xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn31xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn38xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn50xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn52xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn56xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn58xx; - struct cvmx_gmxx_rxx_stats_octs_drp_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_pkts { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_pkts_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_gmxx_rxx_stats_pkts_s cn30xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn31xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn38xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_pkts_s cn50xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn52xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_pkts_s cn56xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_pkts_s cn58xx; - struct cvmx_gmxx_rxx_stats_pkts_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_pkts_bad { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_pkts_bad_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn30xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn31xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn38xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn50xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn52xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn56xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn58xx; - struct cvmx_gmxx_rxx_stats_pkts_bad_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_pkts_ctl { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn30xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn31xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn38xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn50xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn52xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn56xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn58xx; - struct cvmx_gmxx_rxx_stats_pkts_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_pkts_dmac { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn30xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn31xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn38xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn50xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn52xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn56xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn58xx; - struct cvmx_gmxx_rxx_stats_pkts_dmac_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_stats_pkts_drp { - uint64_t u64; - struct cvmx_gmxx_rxx_stats_pkts_drp_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn30xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn31xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn38xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn38xxp2; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn50xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn52xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn52xxp1; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn56xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn56xxp1; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn58xx; - struct cvmx_gmxx_rxx_stats_pkts_drp_s cn58xxp1; -}; - -union cvmx_gmxx_rxx_udd_skp { - uint64_t u64; - struct cvmx_gmxx_rxx_udd_skp_s { - uint64_t reserved_9_63:55; - uint64_t fcssel:1; - uint64_t reserved_7_7:1; - uint64_t len:7; - } s; - struct cvmx_gmxx_rxx_udd_skp_s cn30xx; - struct cvmx_gmxx_rxx_udd_skp_s cn31xx; - struct cvmx_gmxx_rxx_udd_skp_s cn38xx; - struct cvmx_gmxx_rxx_udd_skp_s cn38xxp2; - struct cvmx_gmxx_rxx_udd_skp_s cn50xx; - struct cvmx_gmxx_rxx_udd_skp_s cn52xx; - struct cvmx_gmxx_rxx_udd_skp_s cn52xxp1; - struct cvmx_gmxx_rxx_udd_skp_s cn56xx; - struct cvmx_gmxx_rxx_udd_skp_s cn56xxp1; - struct cvmx_gmxx_rxx_udd_skp_s cn58xx; - struct cvmx_gmxx_rxx_udd_skp_s cn58xxp1; -}; - -union cvmx_gmxx_rx_bp_dropx { - uint64_t u64; - struct cvmx_gmxx_rx_bp_dropx_s { - uint64_t reserved_6_63:58; - uint64_t mark:6; - } s; - struct cvmx_gmxx_rx_bp_dropx_s cn30xx; - struct cvmx_gmxx_rx_bp_dropx_s cn31xx; - struct cvmx_gmxx_rx_bp_dropx_s cn38xx; - struct cvmx_gmxx_rx_bp_dropx_s cn38xxp2; - struct cvmx_gmxx_rx_bp_dropx_s cn50xx; - struct cvmx_gmxx_rx_bp_dropx_s cn52xx; - struct cvmx_gmxx_rx_bp_dropx_s cn52xxp1; - struct cvmx_gmxx_rx_bp_dropx_s cn56xx; - struct cvmx_gmxx_rx_bp_dropx_s cn56xxp1; - struct cvmx_gmxx_rx_bp_dropx_s cn58xx; - struct cvmx_gmxx_rx_bp_dropx_s cn58xxp1; -}; - -union cvmx_gmxx_rx_bp_offx { - uint64_t u64; - struct cvmx_gmxx_rx_bp_offx_s { - uint64_t reserved_6_63:58; - uint64_t mark:6; - } s; - struct cvmx_gmxx_rx_bp_offx_s cn30xx; - struct cvmx_gmxx_rx_bp_offx_s cn31xx; - struct cvmx_gmxx_rx_bp_offx_s cn38xx; - struct cvmx_gmxx_rx_bp_offx_s cn38xxp2; - struct cvmx_gmxx_rx_bp_offx_s cn50xx; - struct cvmx_gmxx_rx_bp_offx_s cn52xx; - struct cvmx_gmxx_rx_bp_offx_s cn52xxp1; - struct cvmx_gmxx_rx_bp_offx_s cn56xx; - struct cvmx_gmxx_rx_bp_offx_s cn56xxp1; - struct cvmx_gmxx_rx_bp_offx_s cn58xx; - struct cvmx_gmxx_rx_bp_offx_s cn58xxp1; -}; - -union cvmx_gmxx_rx_bp_onx { - uint64_t u64; - struct cvmx_gmxx_rx_bp_onx_s { - uint64_t reserved_9_63:55; - uint64_t mark:9; - } s; - struct cvmx_gmxx_rx_bp_onx_s cn30xx; - struct cvmx_gmxx_rx_bp_onx_s cn31xx; - struct cvmx_gmxx_rx_bp_onx_s cn38xx; - struct cvmx_gmxx_rx_bp_onx_s cn38xxp2; - struct cvmx_gmxx_rx_bp_onx_s cn50xx; - struct cvmx_gmxx_rx_bp_onx_s cn52xx; - struct cvmx_gmxx_rx_bp_onx_s cn52xxp1; - struct cvmx_gmxx_rx_bp_onx_s cn56xx; - struct cvmx_gmxx_rx_bp_onx_s cn56xxp1; - struct cvmx_gmxx_rx_bp_onx_s cn58xx; - struct cvmx_gmxx_rx_bp_onx_s cn58xxp1; -}; - -union cvmx_gmxx_rx_hg2_status { - uint64_t u64; - struct cvmx_gmxx_rx_hg2_status_s { - uint64_t reserved_48_63:16; - uint64_t phtim2go:16; - uint64_t xof:16; - uint64_t lgtim2go:16; - } s; - struct cvmx_gmxx_rx_hg2_status_s cn52xx; - struct cvmx_gmxx_rx_hg2_status_s cn52xxp1; - struct cvmx_gmxx_rx_hg2_status_s cn56xx; -}; - -union cvmx_gmxx_rx_pass_en { - uint64_t u64; - struct cvmx_gmxx_rx_pass_en_s { - uint64_t reserved_16_63:48; - uint64_t en:16; - } s; - struct cvmx_gmxx_rx_pass_en_s cn38xx; - struct cvmx_gmxx_rx_pass_en_s cn38xxp2; - struct cvmx_gmxx_rx_pass_en_s cn58xx; - struct cvmx_gmxx_rx_pass_en_s cn58xxp1; -}; - -union cvmx_gmxx_rx_pass_mapx { - uint64_t u64; - struct cvmx_gmxx_rx_pass_mapx_s { - uint64_t reserved_4_63:60; - uint64_t dprt:4; - } s; - struct cvmx_gmxx_rx_pass_mapx_s cn38xx; - struct cvmx_gmxx_rx_pass_mapx_s cn38xxp2; - struct cvmx_gmxx_rx_pass_mapx_s cn58xx; - struct cvmx_gmxx_rx_pass_mapx_s cn58xxp1; -}; - -union cvmx_gmxx_rx_prt_info { - uint64_t u64; - struct cvmx_gmxx_rx_prt_info_s { - uint64_t reserved_32_63:32; - uint64_t drop:16; - uint64_t commit:16; - } s; - struct cvmx_gmxx_rx_prt_info_cn30xx { - uint64_t reserved_19_63:45; - uint64_t drop:3; - uint64_t reserved_3_15:13; - uint64_t commit:3; - } cn30xx; - struct cvmx_gmxx_rx_prt_info_cn30xx cn31xx; - struct cvmx_gmxx_rx_prt_info_s cn38xx; - struct cvmx_gmxx_rx_prt_info_cn30xx cn50xx; - struct cvmx_gmxx_rx_prt_info_cn52xx { - uint64_t reserved_20_63:44; - uint64_t drop:4; - uint64_t reserved_4_15:12; - uint64_t commit:4; - } cn52xx; - struct cvmx_gmxx_rx_prt_info_cn52xx cn52xxp1; - struct cvmx_gmxx_rx_prt_info_cn52xx cn56xx; - struct cvmx_gmxx_rx_prt_info_cn52xx cn56xxp1; - struct cvmx_gmxx_rx_prt_info_s cn58xx; - struct cvmx_gmxx_rx_prt_info_s cn58xxp1; -}; - -union cvmx_gmxx_rx_prts { - uint64_t u64; - struct cvmx_gmxx_rx_prts_s { - uint64_t reserved_3_63:61; - uint64_t prts:3; - } s; - struct cvmx_gmxx_rx_prts_s cn30xx; - struct cvmx_gmxx_rx_prts_s cn31xx; - struct cvmx_gmxx_rx_prts_s cn38xx; - struct cvmx_gmxx_rx_prts_s cn38xxp2; - struct cvmx_gmxx_rx_prts_s cn50xx; - struct cvmx_gmxx_rx_prts_s cn52xx; - struct cvmx_gmxx_rx_prts_s cn52xxp1; - struct cvmx_gmxx_rx_prts_s cn56xx; - struct cvmx_gmxx_rx_prts_s cn56xxp1; - struct cvmx_gmxx_rx_prts_s cn58xx; - struct cvmx_gmxx_rx_prts_s cn58xxp1; -}; - -union cvmx_gmxx_rx_tx_status { - uint64_t u64; - struct cvmx_gmxx_rx_tx_status_s { - uint64_t reserved_7_63:57; - uint64_t tx:3; - uint64_t reserved_3_3:1; - uint64_t rx:3; - } s; - struct cvmx_gmxx_rx_tx_status_s cn30xx; - struct cvmx_gmxx_rx_tx_status_s cn31xx; - struct cvmx_gmxx_rx_tx_status_s cn50xx; -}; - -union cvmx_gmxx_rx_xaui_bad_col { - uint64_t u64; - struct cvmx_gmxx_rx_xaui_bad_col_s { - uint64_t reserved_40_63:24; - uint64_t val:1; - uint64_t state:3; - uint64_t lane_rxc:4; - uint64_t lane_rxd:32; - } s; - struct cvmx_gmxx_rx_xaui_bad_col_s cn52xx; - struct cvmx_gmxx_rx_xaui_bad_col_s cn52xxp1; - struct cvmx_gmxx_rx_xaui_bad_col_s cn56xx; - struct cvmx_gmxx_rx_xaui_bad_col_s cn56xxp1; -}; - -union cvmx_gmxx_rx_xaui_ctl { - uint64_t u64; - struct cvmx_gmxx_rx_xaui_ctl_s { - uint64_t reserved_2_63:62; - uint64_t status:2; - } s; - struct cvmx_gmxx_rx_xaui_ctl_s cn52xx; - struct cvmx_gmxx_rx_xaui_ctl_s cn52xxp1; - struct cvmx_gmxx_rx_xaui_ctl_s cn56xx; - struct cvmx_gmxx_rx_xaui_ctl_s cn56xxp1; -}; - -union cvmx_gmxx_smacx { - uint64_t u64; - struct cvmx_gmxx_smacx_s { - uint64_t reserved_48_63:16; - uint64_t smac:48; - } s; - struct cvmx_gmxx_smacx_s cn30xx; - struct cvmx_gmxx_smacx_s cn31xx; - struct cvmx_gmxx_smacx_s cn38xx; - struct cvmx_gmxx_smacx_s cn38xxp2; - struct cvmx_gmxx_smacx_s cn50xx; - struct cvmx_gmxx_smacx_s cn52xx; - struct cvmx_gmxx_smacx_s cn52xxp1; - struct cvmx_gmxx_smacx_s cn56xx; - struct cvmx_gmxx_smacx_s cn56xxp1; - struct cvmx_gmxx_smacx_s cn58xx; - struct cvmx_gmxx_smacx_s cn58xxp1; -}; - -union cvmx_gmxx_stat_bp { - uint64_t u64; - struct cvmx_gmxx_stat_bp_s { - uint64_t reserved_17_63:47; - uint64_t bp:1; - uint64_t cnt:16; - } s; - struct cvmx_gmxx_stat_bp_s cn30xx; - struct cvmx_gmxx_stat_bp_s cn31xx; - struct cvmx_gmxx_stat_bp_s cn38xx; - struct cvmx_gmxx_stat_bp_s cn38xxp2; - struct cvmx_gmxx_stat_bp_s cn50xx; - struct cvmx_gmxx_stat_bp_s cn52xx; - struct cvmx_gmxx_stat_bp_s cn52xxp1; - struct cvmx_gmxx_stat_bp_s cn56xx; - struct cvmx_gmxx_stat_bp_s cn56xxp1; - struct cvmx_gmxx_stat_bp_s cn58xx; - struct cvmx_gmxx_stat_bp_s cn58xxp1; -}; - -union cvmx_gmxx_txx_append { - uint64_t u64; - struct cvmx_gmxx_txx_append_s { - uint64_t reserved_4_63:60; - uint64_t force_fcs:1; - uint64_t fcs:1; - uint64_t pad:1; - uint64_t preamble:1; - } s; - struct cvmx_gmxx_txx_append_s cn30xx; - struct cvmx_gmxx_txx_append_s cn31xx; - struct cvmx_gmxx_txx_append_s cn38xx; - struct cvmx_gmxx_txx_append_s cn38xxp2; - struct cvmx_gmxx_txx_append_s cn50xx; - struct cvmx_gmxx_txx_append_s cn52xx; - struct cvmx_gmxx_txx_append_s cn52xxp1; - struct cvmx_gmxx_txx_append_s cn56xx; - struct cvmx_gmxx_txx_append_s cn56xxp1; - struct cvmx_gmxx_txx_append_s cn58xx; - struct cvmx_gmxx_txx_append_s cn58xxp1; -}; - -union cvmx_gmxx_txx_burst { - uint64_t u64; - struct cvmx_gmxx_txx_burst_s { - uint64_t reserved_16_63:48; - uint64_t burst:16; - } s; - struct cvmx_gmxx_txx_burst_s cn30xx; - struct cvmx_gmxx_txx_burst_s cn31xx; - struct cvmx_gmxx_txx_burst_s cn38xx; - struct cvmx_gmxx_txx_burst_s cn38xxp2; - struct cvmx_gmxx_txx_burst_s cn50xx; - struct cvmx_gmxx_txx_burst_s cn52xx; - struct cvmx_gmxx_txx_burst_s cn52xxp1; - struct cvmx_gmxx_txx_burst_s cn56xx; - struct cvmx_gmxx_txx_burst_s cn56xxp1; - struct cvmx_gmxx_txx_burst_s cn58xx; - struct cvmx_gmxx_txx_burst_s cn58xxp1; -}; - -union cvmx_gmxx_txx_cbfc_xoff { - uint64_t u64; - struct cvmx_gmxx_txx_cbfc_xoff_s { - uint64_t reserved_16_63:48; - uint64_t xoff:16; - } s; - struct cvmx_gmxx_txx_cbfc_xoff_s cn52xx; - struct cvmx_gmxx_txx_cbfc_xoff_s cn56xx; -}; - -union cvmx_gmxx_txx_cbfc_xon { - uint64_t u64; - struct cvmx_gmxx_txx_cbfc_xon_s { - uint64_t reserved_16_63:48; - uint64_t xon:16; - } s; - struct cvmx_gmxx_txx_cbfc_xon_s cn52xx; - struct cvmx_gmxx_txx_cbfc_xon_s cn56xx; -}; - -union cvmx_gmxx_txx_clk { - uint64_t u64; - struct cvmx_gmxx_txx_clk_s { - uint64_t reserved_6_63:58; - uint64_t clk_cnt:6; - } s; - struct cvmx_gmxx_txx_clk_s cn30xx; - struct cvmx_gmxx_txx_clk_s cn31xx; - struct cvmx_gmxx_txx_clk_s cn38xx; - struct cvmx_gmxx_txx_clk_s cn38xxp2; - struct cvmx_gmxx_txx_clk_s cn50xx; - struct cvmx_gmxx_txx_clk_s cn58xx; - struct cvmx_gmxx_txx_clk_s cn58xxp1; -}; - -union cvmx_gmxx_txx_ctl { - uint64_t u64; - struct cvmx_gmxx_txx_ctl_s { - uint64_t reserved_2_63:62; - uint64_t xsdef_en:1; - uint64_t xscol_en:1; - } s; - struct cvmx_gmxx_txx_ctl_s cn30xx; - struct cvmx_gmxx_txx_ctl_s cn31xx; - struct cvmx_gmxx_txx_ctl_s cn38xx; - struct cvmx_gmxx_txx_ctl_s cn38xxp2; - struct cvmx_gmxx_txx_ctl_s cn50xx; - struct cvmx_gmxx_txx_ctl_s cn52xx; - struct cvmx_gmxx_txx_ctl_s cn52xxp1; - struct cvmx_gmxx_txx_ctl_s cn56xx; - struct cvmx_gmxx_txx_ctl_s cn56xxp1; - struct cvmx_gmxx_txx_ctl_s cn58xx; - struct cvmx_gmxx_txx_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_txx_min_pkt { - uint64_t u64; - struct cvmx_gmxx_txx_min_pkt_s { - uint64_t reserved_8_63:56; - uint64_t min_size:8; - } s; - struct cvmx_gmxx_txx_min_pkt_s cn30xx; - struct cvmx_gmxx_txx_min_pkt_s cn31xx; - struct cvmx_gmxx_txx_min_pkt_s cn38xx; - struct cvmx_gmxx_txx_min_pkt_s cn38xxp2; - struct cvmx_gmxx_txx_min_pkt_s cn50xx; - struct cvmx_gmxx_txx_min_pkt_s cn52xx; - struct cvmx_gmxx_txx_min_pkt_s cn52xxp1; - struct cvmx_gmxx_txx_min_pkt_s cn56xx; - struct cvmx_gmxx_txx_min_pkt_s cn56xxp1; - struct cvmx_gmxx_txx_min_pkt_s cn58xx; - struct cvmx_gmxx_txx_min_pkt_s cn58xxp1; -}; - -union cvmx_gmxx_txx_pause_pkt_interval { - uint64_t u64; - struct cvmx_gmxx_txx_pause_pkt_interval_s { - uint64_t reserved_16_63:48; - uint64_t interval:16; - } s; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn30xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn31xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn38xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn38xxp2; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn50xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn52xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn52xxp1; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn56xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn56xxp1; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn58xx; - struct cvmx_gmxx_txx_pause_pkt_interval_s cn58xxp1; -}; - -union cvmx_gmxx_txx_pause_pkt_time { - uint64_t u64; - struct cvmx_gmxx_txx_pause_pkt_time_s { - uint64_t reserved_16_63:48; - uint64_t time:16; - } s; - struct cvmx_gmxx_txx_pause_pkt_time_s cn30xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn31xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn38xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn38xxp2; - struct cvmx_gmxx_txx_pause_pkt_time_s cn50xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn52xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn52xxp1; - struct cvmx_gmxx_txx_pause_pkt_time_s cn56xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn56xxp1; - struct cvmx_gmxx_txx_pause_pkt_time_s cn58xx; - struct cvmx_gmxx_txx_pause_pkt_time_s cn58xxp1; -}; - -union cvmx_gmxx_txx_pause_togo { - uint64_t u64; - struct cvmx_gmxx_txx_pause_togo_s { - uint64_t reserved_32_63:32; - uint64_t msg_time:16; - uint64_t time:16; - } s; - struct cvmx_gmxx_txx_pause_togo_cn30xx { - uint64_t reserved_16_63:48; - uint64_t time:16; - } cn30xx; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn31xx; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn38xx; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn38xxp2; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn50xx; - struct cvmx_gmxx_txx_pause_togo_s cn52xx; - struct cvmx_gmxx_txx_pause_togo_s cn52xxp1; - struct cvmx_gmxx_txx_pause_togo_s cn56xx; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn56xxp1; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn58xx; - struct cvmx_gmxx_txx_pause_togo_cn30xx cn58xxp1; -}; - -union cvmx_gmxx_txx_pause_zero { - uint64_t u64; - struct cvmx_gmxx_txx_pause_zero_s { - uint64_t reserved_1_63:63; - uint64_t send:1; - } s; - struct cvmx_gmxx_txx_pause_zero_s cn30xx; - struct cvmx_gmxx_txx_pause_zero_s cn31xx; - struct cvmx_gmxx_txx_pause_zero_s cn38xx; - struct cvmx_gmxx_txx_pause_zero_s cn38xxp2; - struct cvmx_gmxx_txx_pause_zero_s cn50xx; - struct cvmx_gmxx_txx_pause_zero_s cn52xx; - struct cvmx_gmxx_txx_pause_zero_s cn52xxp1; - struct cvmx_gmxx_txx_pause_zero_s cn56xx; - struct cvmx_gmxx_txx_pause_zero_s cn56xxp1; - struct cvmx_gmxx_txx_pause_zero_s cn58xx; - struct cvmx_gmxx_txx_pause_zero_s cn58xxp1; -}; - -union cvmx_gmxx_txx_sgmii_ctl { - uint64_t u64; - struct cvmx_gmxx_txx_sgmii_ctl_s { - uint64_t reserved_1_63:63; - uint64_t align:1; - } s; - struct cvmx_gmxx_txx_sgmii_ctl_s cn52xx; - struct cvmx_gmxx_txx_sgmii_ctl_s cn52xxp1; - struct cvmx_gmxx_txx_sgmii_ctl_s cn56xx; - struct cvmx_gmxx_txx_sgmii_ctl_s cn56xxp1; -}; - -union cvmx_gmxx_txx_slot { - uint64_t u64; - struct cvmx_gmxx_txx_slot_s { - uint64_t reserved_10_63:54; - uint64_t slot:10; - } s; - struct cvmx_gmxx_txx_slot_s cn30xx; - struct cvmx_gmxx_txx_slot_s cn31xx; - struct cvmx_gmxx_txx_slot_s cn38xx; - struct cvmx_gmxx_txx_slot_s cn38xxp2; - struct cvmx_gmxx_txx_slot_s cn50xx; - struct cvmx_gmxx_txx_slot_s cn52xx; - struct cvmx_gmxx_txx_slot_s cn52xxp1; - struct cvmx_gmxx_txx_slot_s cn56xx; - struct cvmx_gmxx_txx_slot_s cn56xxp1; - struct cvmx_gmxx_txx_slot_s cn58xx; - struct cvmx_gmxx_txx_slot_s cn58xxp1; -}; - -union cvmx_gmxx_txx_soft_pause { - uint64_t u64; - struct cvmx_gmxx_txx_soft_pause_s { - uint64_t reserved_16_63:48; - uint64_t time:16; - } s; - struct cvmx_gmxx_txx_soft_pause_s cn30xx; - struct cvmx_gmxx_txx_soft_pause_s cn31xx; - struct cvmx_gmxx_txx_soft_pause_s cn38xx; - struct cvmx_gmxx_txx_soft_pause_s cn38xxp2; - struct cvmx_gmxx_txx_soft_pause_s cn50xx; - struct cvmx_gmxx_txx_soft_pause_s cn52xx; - struct cvmx_gmxx_txx_soft_pause_s cn52xxp1; - struct cvmx_gmxx_txx_soft_pause_s cn56xx; - struct cvmx_gmxx_txx_soft_pause_s cn56xxp1; - struct cvmx_gmxx_txx_soft_pause_s cn58xx; - struct cvmx_gmxx_txx_soft_pause_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat0 { - uint64_t u64; - struct cvmx_gmxx_txx_stat0_s { - uint64_t xsdef:32; - uint64_t xscol:32; - } s; - struct cvmx_gmxx_txx_stat0_s cn30xx; - struct cvmx_gmxx_txx_stat0_s cn31xx; - struct cvmx_gmxx_txx_stat0_s cn38xx; - struct cvmx_gmxx_txx_stat0_s cn38xxp2; - struct cvmx_gmxx_txx_stat0_s cn50xx; - struct cvmx_gmxx_txx_stat0_s cn52xx; - struct cvmx_gmxx_txx_stat0_s cn52xxp1; - struct cvmx_gmxx_txx_stat0_s cn56xx; - struct cvmx_gmxx_txx_stat0_s cn56xxp1; - struct cvmx_gmxx_txx_stat0_s cn58xx; - struct cvmx_gmxx_txx_stat0_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat1 { - uint64_t u64; - struct cvmx_gmxx_txx_stat1_s { - uint64_t scol:32; - uint64_t mcol:32; - } s; - struct cvmx_gmxx_txx_stat1_s cn30xx; - struct cvmx_gmxx_txx_stat1_s cn31xx; - struct cvmx_gmxx_txx_stat1_s cn38xx; - struct cvmx_gmxx_txx_stat1_s cn38xxp2; - struct cvmx_gmxx_txx_stat1_s cn50xx; - struct cvmx_gmxx_txx_stat1_s cn52xx; - struct cvmx_gmxx_txx_stat1_s cn52xxp1; - struct cvmx_gmxx_txx_stat1_s cn56xx; - struct cvmx_gmxx_txx_stat1_s cn56xxp1; - struct cvmx_gmxx_txx_stat1_s cn58xx; - struct cvmx_gmxx_txx_stat1_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat2 { - uint64_t u64; - struct cvmx_gmxx_txx_stat2_s { - uint64_t reserved_48_63:16; - uint64_t octs:48; - } s; - struct cvmx_gmxx_txx_stat2_s cn30xx; - struct cvmx_gmxx_txx_stat2_s cn31xx; - struct cvmx_gmxx_txx_stat2_s cn38xx; - struct cvmx_gmxx_txx_stat2_s cn38xxp2; - struct cvmx_gmxx_txx_stat2_s cn50xx; - struct cvmx_gmxx_txx_stat2_s cn52xx; - struct cvmx_gmxx_txx_stat2_s cn52xxp1; - struct cvmx_gmxx_txx_stat2_s cn56xx; - struct cvmx_gmxx_txx_stat2_s cn56xxp1; - struct cvmx_gmxx_txx_stat2_s cn58xx; - struct cvmx_gmxx_txx_stat2_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat3 { - uint64_t u64; - struct cvmx_gmxx_txx_stat3_s { - uint64_t reserved_32_63:32; - uint64_t pkts:32; - } s; - struct cvmx_gmxx_txx_stat3_s cn30xx; - struct cvmx_gmxx_txx_stat3_s cn31xx; - struct cvmx_gmxx_txx_stat3_s cn38xx; - struct cvmx_gmxx_txx_stat3_s cn38xxp2; - struct cvmx_gmxx_txx_stat3_s cn50xx; - struct cvmx_gmxx_txx_stat3_s cn52xx; - struct cvmx_gmxx_txx_stat3_s cn52xxp1; - struct cvmx_gmxx_txx_stat3_s cn56xx; - struct cvmx_gmxx_txx_stat3_s cn56xxp1; - struct cvmx_gmxx_txx_stat3_s cn58xx; - struct cvmx_gmxx_txx_stat3_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat4 { - uint64_t u64; - struct cvmx_gmxx_txx_stat4_s { - uint64_t hist1:32; - uint64_t hist0:32; - } s; - struct cvmx_gmxx_txx_stat4_s cn30xx; - struct cvmx_gmxx_txx_stat4_s cn31xx; - struct cvmx_gmxx_txx_stat4_s cn38xx; - struct cvmx_gmxx_txx_stat4_s cn38xxp2; - struct cvmx_gmxx_txx_stat4_s cn50xx; - struct cvmx_gmxx_txx_stat4_s cn52xx; - struct cvmx_gmxx_txx_stat4_s cn52xxp1; - struct cvmx_gmxx_txx_stat4_s cn56xx; - struct cvmx_gmxx_txx_stat4_s cn56xxp1; - struct cvmx_gmxx_txx_stat4_s cn58xx; - struct cvmx_gmxx_txx_stat4_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat5 { - uint64_t u64; - struct cvmx_gmxx_txx_stat5_s { - uint64_t hist3:32; - uint64_t hist2:32; - } s; - struct cvmx_gmxx_txx_stat5_s cn30xx; - struct cvmx_gmxx_txx_stat5_s cn31xx; - struct cvmx_gmxx_txx_stat5_s cn38xx; - struct cvmx_gmxx_txx_stat5_s cn38xxp2; - struct cvmx_gmxx_txx_stat5_s cn50xx; - struct cvmx_gmxx_txx_stat5_s cn52xx; - struct cvmx_gmxx_txx_stat5_s cn52xxp1; - struct cvmx_gmxx_txx_stat5_s cn56xx; - struct cvmx_gmxx_txx_stat5_s cn56xxp1; - struct cvmx_gmxx_txx_stat5_s cn58xx; - struct cvmx_gmxx_txx_stat5_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat6 { - uint64_t u64; - struct cvmx_gmxx_txx_stat6_s { - uint64_t hist5:32; - uint64_t hist4:32; - } s; - struct cvmx_gmxx_txx_stat6_s cn30xx; - struct cvmx_gmxx_txx_stat6_s cn31xx; - struct cvmx_gmxx_txx_stat6_s cn38xx; - struct cvmx_gmxx_txx_stat6_s cn38xxp2; - struct cvmx_gmxx_txx_stat6_s cn50xx; - struct cvmx_gmxx_txx_stat6_s cn52xx; - struct cvmx_gmxx_txx_stat6_s cn52xxp1; - struct cvmx_gmxx_txx_stat6_s cn56xx; - struct cvmx_gmxx_txx_stat6_s cn56xxp1; - struct cvmx_gmxx_txx_stat6_s cn58xx; - struct cvmx_gmxx_txx_stat6_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat7 { - uint64_t u64; - struct cvmx_gmxx_txx_stat7_s { - uint64_t hist7:32; - uint64_t hist6:32; - } s; - struct cvmx_gmxx_txx_stat7_s cn30xx; - struct cvmx_gmxx_txx_stat7_s cn31xx; - struct cvmx_gmxx_txx_stat7_s cn38xx; - struct cvmx_gmxx_txx_stat7_s cn38xxp2; - struct cvmx_gmxx_txx_stat7_s cn50xx; - struct cvmx_gmxx_txx_stat7_s cn52xx; - struct cvmx_gmxx_txx_stat7_s cn52xxp1; - struct cvmx_gmxx_txx_stat7_s cn56xx; - struct cvmx_gmxx_txx_stat7_s cn56xxp1; - struct cvmx_gmxx_txx_stat7_s cn58xx; - struct cvmx_gmxx_txx_stat7_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat8 { - uint64_t u64; - struct cvmx_gmxx_txx_stat8_s { - uint64_t mcst:32; - uint64_t bcst:32; - } s; - struct cvmx_gmxx_txx_stat8_s cn30xx; - struct cvmx_gmxx_txx_stat8_s cn31xx; - struct cvmx_gmxx_txx_stat8_s cn38xx; - struct cvmx_gmxx_txx_stat8_s cn38xxp2; - struct cvmx_gmxx_txx_stat8_s cn50xx; - struct cvmx_gmxx_txx_stat8_s cn52xx; - struct cvmx_gmxx_txx_stat8_s cn52xxp1; - struct cvmx_gmxx_txx_stat8_s cn56xx; - struct cvmx_gmxx_txx_stat8_s cn56xxp1; - struct cvmx_gmxx_txx_stat8_s cn58xx; - struct cvmx_gmxx_txx_stat8_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stat9 { - uint64_t u64; - struct cvmx_gmxx_txx_stat9_s { - uint64_t undflw:32; - uint64_t ctl:32; - } s; - struct cvmx_gmxx_txx_stat9_s cn30xx; - struct cvmx_gmxx_txx_stat9_s cn31xx; - struct cvmx_gmxx_txx_stat9_s cn38xx; - struct cvmx_gmxx_txx_stat9_s cn38xxp2; - struct cvmx_gmxx_txx_stat9_s cn50xx; - struct cvmx_gmxx_txx_stat9_s cn52xx; - struct cvmx_gmxx_txx_stat9_s cn52xxp1; - struct cvmx_gmxx_txx_stat9_s cn56xx; - struct cvmx_gmxx_txx_stat9_s cn56xxp1; - struct cvmx_gmxx_txx_stat9_s cn58xx; - struct cvmx_gmxx_txx_stat9_s cn58xxp1; -}; - -union cvmx_gmxx_txx_stats_ctl { - uint64_t u64; - struct cvmx_gmxx_txx_stats_ctl_s { - uint64_t reserved_1_63:63; - uint64_t rd_clr:1; - } s; - struct cvmx_gmxx_txx_stats_ctl_s cn30xx; - struct cvmx_gmxx_txx_stats_ctl_s cn31xx; - struct cvmx_gmxx_txx_stats_ctl_s cn38xx; - struct cvmx_gmxx_txx_stats_ctl_s cn38xxp2; - struct cvmx_gmxx_txx_stats_ctl_s cn50xx; - struct cvmx_gmxx_txx_stats_ctl_s cn52xx; - struct cvmx_gmxx_txx_stats_ctl_s cn52xxp1; - struct cvmx_gmxx_txx_stats_ctl_s cn56xx; - struct cvmx_gmxx_txx_stats_ctl_s cn56xxp1; - struct cvmx_gmxx_txx_stats_ctl_s cn58xx; - struct cvmx_gmxx_txx_stats_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_txx_thresh { - uint64_t u64; - struct cvmx_gmxx_txx_thresh_s { - uint64_t reserved_9_63:55; - uint64_t cnt:9; - } s; - struct cvmx_gmxx_txx_thresh_cn30xx { - uint64_t reserved_7_63:57; - uint64_t cnt:7; - } cn30xx; - struct cvmx_gmxx_txx_thresh_cn30xx cn31xx; - struct cvmx_gmxx_txx_thresh_s cn38xx; - struct cvmx_gmxx_txx_thresh_s cn38xxp2; - struct cvmx_gmxx_txx_thresh_cn30xx cn50xx; - struct cvmx_gmxx_txx_thresh_s cn52xx; - struct cvmx_gmxx_txx_thresh_s cn52xxp1; - struct cvmx_gmxx_txx_thresh_s cn56xx; - struct cvmx_gmxx_txx_thresh_s cn56xxp1; - struct cvmx_gmxx_txx_thresh_s cn58xx; - struct cvmx_gmxx_txx_thresh_s cn58xxp1; -}; - -union cvmx_gmxx_tx_bp { - uint64_t u64; - struct cvmx_gmxx_tx_bp_s { - uint64_t reserved_4_63:60; - uint64_t bp:4; - } s; - struct cvmx_gmxx_tx_bp_cn30xx { - uint64_t reserved_3_63:61; - uint64_t bp:3; - } cn30xx; - struct cvmx_gmxx_tx_bp_cn30xx cn31xx; - struct cvmx_gmxx_tx_bp_s cn38xx; - struct cvmx_gmxx_tx_bp_s cn38xxp2; - struct cvmx_gmxx_tx_bp_cn30xx cn50xx; - struct cvmx_gmxx_tx_bp_s cn52xx; - struct cvmx_gmxx_tx_bp_s cn52xxp1; - struct cvmx_gmxx_tx_bp_s cn56xx; - struct cvmx_gmxx_tx_bp_s cn56xxp1; - struct cvmx_gmxx_tx_bp_s cn58xx; - struct cvmx_gmxx_tx_bp_s cn58xxp1; -}; - -union cvmx_gmxx_tx_clk_mskx { - uint64_t u64; - struct cvmx_gmxx_tx_clk_mskx_s { - uint64_t reserved_1_63:63; - uint64_t msk:1; - } s; - struct cvmx_gmxx_tx_clk_mskx_s cn30xx; - struct cvmx_gmxx_tx_clk_mskx_s cn50xx; -}; - -union cvmx_gmxx_tx_col_attempt { - uint64_t u64; - struct cvmx_gmxx_tx_col_attempt_s { - uint64_t reserved_5_63:59; - uint64_t limit:5; - } s; - struct cvmx_gmxx_tx_col_attempt_s cn30xx; - struct cvmx_gmxx_tx_col_attempt_s cn31xx; - struct cvmx_gmxx_tx_col_attempt_s cn38xx; - struct cvmx_gmxx_tx_col_attempt_s cn38xxp2; - struct cvmx_gmxx_tx_col_attempt_s cn50xx; - struct cvmx_gmxx_tx_col_attempt_s cn52xx; - struct cvmx_gmxx_tx_col_attempt_s cn52xxp1; - struct cvmx_gmxx_tx_col_attempt_s cn56xx; - struct cvmx_gmxx_tx_col_attempt_s cn56xxp1; - struct cvmx_gmxx_tx_col_attempt_s cn58xx; - struct cvmx_gmxx_tx_col_attempt_s cn58xxp1; -}; - -union cvmx_gmxx_tx_corrupt { - uint64_t u64; - struct cvmx_gmxx_tx_corrupt_s { - uint64_t reserved_4_63:60; - uint64_t corrupt:4; - } s; - struct cvmx_gmxx_tx_corrupt_cn30xx { - uint64_t reserved_3_63:61; - uint64_t corrupt:3; - } cn30xx; - struct cvmx_gmxx_tx_corrupt_cn30xx cn31xx; - struct cvmx_gmxx_tx_corrupt_s cn38xx; - struct cvmx_gmxx_tx_corrupt_s cn38xxp2; - struct cvmx_gmxx_tx_corrupt_cn30xx cn50xx; - struct cvmx_gmxx_tx_corrupt_s cn52xx; - struct cvmx_gmxx_tx_corrupt_s cn52xxp1; - struct cvmx_gmxx_tx_corrupt_s cn56xx; - struct cvmx_gmxx_tx_corrupt_s cn56xxp1; - struct cvmx_gmxx_tx_corrupt_s cn58xx; - struct cvmx_gmxx_tx_corrupt_s cn58xxp1; -}; - -union cvmx_gmxx_tx_hg2_reg1 { - uint64_t u64; - struct cvmx_gmxx_tx_hg2_reg1_s { - uint64_t reserved_16_63:48; - uint64_t tx_xof:16; - } s; - struct cvmx_gmxx_tx_hg2_reg1_s cn52xx; - struct cvmx_gmxx_tx_hg2_reg1_s cn52xxp1; - struct cvmx_gmxx_tx_hg2_reg1_s cn56xx; -}; - -union cvmx_gmxx_tx_hg2_reg2 { - uint64_t u64; - struct cvmx_gmxx_tx_hg2_reg2_s { - uint64_t reserved_16_63:48; - uint64_t tx_xon:16; - } s; - struct cvmx_gmxx_tx_hg2_reg2_s cn52xx; - struct cvmx_gmxx_tx_hg2_reg2_s cn52xxp1; - struct cvmx_gmxx_tx_hg2_reg2_s cn56xx; -}; - -union cvmx_gmxx_tx_ifg { - uint64_t u64; - struct cvmx_gmxx_tx_ifg_s { - uint64_t reserved_8_63:56; - uint64_t ifg2:4; - uint64_t ifg1:4; - } s; - struct cvmx_gmxx_tx_ifg_s cn30xx; - struct cvmx_gmxx_tx_ifg_s cn31xx; - struct cvmx_gmxx_tx_ifg_s cn38xx; - struct cvmx_gmxx_tx_ifg_s cn38xxp2; - struct cvmx_gmxx_tx_ifg_s cn50xx; - struct cvmx_gmxx_tx_ifg_s cn52xx; - struct cvmx_gmxx_tx_ifg_s cn52xxp1; - struct cvmx_gmxx_tx_ifg_s cn56xx; - struct cvmx_gmxx_tx_ifg_s cn56xxp1; - struct cvmx_gmxx_tx_ifg_s cn58xx; - struct cvmx_gmxx_tx_ifg_s cn58xxp1; -}; - -union cvmx_gmxx_tx_int_en { - uint64_t u64; - struct cvmx_gmxx_tx_int_en_s { - uint64_t reserved_20_63:44; - uint64_t late_col:4; - uint64_t xsdef:4; - uint64_t xscol:4; - uint64_t reserved_6_7:2; - uint64_t undflw:4; - uint64_t ncb_nxa:1; - uint64_t pko_nxa:1; - } s; - struct cvmx_gmxx_tx_int_en_cn30xx { - uint64_t reserved_19_63:45; - uint64_t late_col:3; - uint64_t reserved_15_15:1; - uint64_t xsdef:3; - uint64_t reserved_11_11:1; - uint64_t xscol:3; - uint64_t reserved_5_7:3; - uint64_t undflw:3; - uint64_t reserved_1_1:1; - uint64_t pko_nxa:1; - } cn30xx; - struct cvmx_gmxx_tx_int_en_cn31xx { - uint64_t reserved_15_63:49; - uint64_t xsdef:3; - uint64_t reserved_11_11:1; - uint64_t xscol:3; - uint64_t reserved_5_7:3; - uint64_t undflw:3; - uint64_t reserved_1_1:1; - uint64_t pko_nxa:1; - } cn31xx; - struct cvmx_gmxx_tx_int_en_s cn38xx; - struct cvmx_gmxx_tx_int_en_cn38xxp2 { - uint64_t reserved_16_63:48; - uint64_t xsdef:4; - uint64_t xscol:4; - uint64_t reserved_6_7:2; - uint64_t undflw:4; - uint64_t ncb_nxa:1; - uint64_t pko_nxa:1; - } cn38xxp2; - struct cvmx_gmxx_tx_int_en_cn30xx cn50xx; - struct cvmx_gmxx_tx_int_en_cn52xx { - uint64_t reserved_20_63:44; - uint64_t late_col:4; - uint64_t xsdef:4; - uint64_t xscol:4; - uint64_t reserved_6_7:2; - uint64_t undflw:4; - uint64_t reserved_1_1:1; - uint64_t pko_nxa:1; - } cn52xx; - struct cvmx_gmxx_tx_int_en_cn52xx cn52xxp1; - struct cvmx_gmxx_tx_int_en_cn52xx cn56xx; - struct cvmx_gmxx_tx_int_en_cn52xx cn56xxp1; - struct cvmx_gmxx_tx_int_en_s cn58xx; - struct cvmx_gmxx_tx_int_en_s cn58xxp1; -}; - -union cvmx_gmxx_tx_int_reg { - uint64_t u64; - struct cvmx_gmxx_tx_int_reg_s { - uint64_t reserved_20_63:44; - uint64_t late_col:4; - uint64_t xsdef:4; - uint64_t xscol:4; - uint64_t reserved_6_7:2; - uint64_t undflw:4; - uint64_t ncb_nxa:1; - uint64_t pko_nxa:1; - } s; - struct cvmx_gmxx_tx_int_reg_cn30xx { - uint64_t reserved_19_63:45; - uint64_t late_col:3; - uint64_t reserved_15_15:1; - uint64_t xsdef:3; - uint64_t reserved_11_11:1; - uint64_t xscol:3; - uint64_t reserved_5_7:3; - uint64_t undflw:3; - uint64_t reserved_1_1:1; - uint64_t pko_nxa:1; - } cn30xx; - struct cvmx_gmxx_tx_int_reg_cn31xx { - uint64_t reserved_15_63:49; - uint64_t xsdef:3; - uint64_t reserved_11_11:1; - uint64_t xscol:3; - uint64_t reserved_5_7:3; - uint64_t undflw:3; - uint64_t reserved_1_1:1; - uint64_t pko_nxa:1; - } cn31xx; - struct cvmx_gmxx_tx_int_reg_s cn38xx; - struct cvmx_gmxx_tx_int_reg_cn38xxp2 { - uint64_t reserved_16_63:48; - uint64_t xsdef:4; - uint64_t xscol:4; - uint64_t reserved_6_7:2; - uint64_t undflw:4; - uint64_t ncb_nxa:1; - uint64_t pko_nxa:1; - } cn38xxp2; - struct cvmx_gmxx_tx_int_reg_cn30xx cn50xx; - struct cvmx_gmxx_tx_int_reg_cn52xx { - uint64_t reserved_20_63:44; - uint64_t late_col:4; - uint64_t xsdef:4; - uint64_t xscol:4; - uint64_t reserved_6_7:2; - uint64_t undflw:4; - uint64_t reserved_1_1:1; - uint64_t pko_nxa:1; - } cn52xx; - struct cvmx_gmxx_tx_int_reg_cn52xx cn52xxp1; - struct cvmx_gmxx_tx_int_reg_cn52xx cn56xx; - struct cvmx_gmxx_tx_int_reg_cn52xx cn56xxp1; - struct cvmx_gmxx_tx_int_reg_s cn58xx; - struct cvmx_gmxx_tx_int_reg_s cn58xxp1; -}; - -union cvmx_gmxx_tx_jam { - uint64_t u64; - struct cvmx_gmxx_tx_jam_s { - uint64_t reserved_8_63:56; - uint64_t jam:8; - } s; - struct cvmx_gmxx_tx_jam_s cn30xx; - struct cvmx_gmxx_tx_jam_s cn31xx; - struct cvmx_gmxx_tx_jam_s cn38xx; - struct cvmx_gmxx_tx_jam_s cn38xxp2; - struct cvmx_gmxx_tx_jam_s cn50xx; - struct cvmx_gmxx_tx_jam_s cn52xx; - struct cvmx_gmxx_tx_jam_s cn52xxp1; - struct cvmx_gmxx_tx_jam_s cn56xx; - struct cvmx_gmxx_tx_jam_s cn56xxp1; - struct cvmx_gmxx_tx_jam_s cn58xx; - struct cvmx_gmxx_tx_jam_s cn58xxp1; -}; - -union cvmx_gmxx_tx_lfsr { - uint64_t u64; - struct cvmx_gmxx_tx_lfsr_s { - uint64_t reserved_16_63:48; - uint64_t lfsr:16; - } s; - struct cvmx_gmxx_tx_lfsr_s cn30xx; - struct cvmx_gmxx_tx_lfsr_s cn31xx; - struct cvmx_gmxx_tx_lfsr_s cn38xx; - struct cvmx_gmxx_tx_lfsr_s cn38xxp2; - struct cvmx_gmxx_tx_lfsr_s cn50xx; - struct cvmx_gmxx_tx_lfsr_s cn52xx; - struct cvmx_gmxx_tx_lfsr_s cn52xxp1; - struct cvmx_gmxx_tx_lfsr_s cn56xx; - struct cvmx_gmxx_tx_lfsr_s cn56xxp1; - struct cvmx_gmxx_tx_lfsr_s cn58xx; - struct cvmx_gmxx_tx_lfsr_s cn58xxp1; -}; - -union cvmx_gmxx_tx_ovr_bp { - uint64_t u64; - struct cvmx_gmxx_tx_ovr_bp_s { - uint64_t reserved_48_63:16; - uint64_t tx_prt_bp:16; - uint64_t reserved_12_31:20; - uint64_t en:4; - uint64_t bp:4; - uint64_t ign_full:4; - } s; - struct cvmx_gmxx_tx_ovr_bp_cn30xx { - uint64_t reserved_11_63:53; - uint64_t en:3; - uint64_t reserved_7_7:1; - uint64_t bp:3; - uint64_t reserved_3_3:1; - uint64_t ign_full:3; - } cn30xx; - struct cvmx_gmxx_tx_ovr_bp_cn30xx cn31xx; - struct cvmx_gmxx_tx_ovr_bp_cn38xx { - uint64_t reserved_12_63:52; - uint64_t en:4; - uint64_t bp:4; - uint64_t ign_full:4; - } cn38xx; - struct cvmx_gmxx_tx_ovr_bp_cn38xx cn38xxp2; - struct cvmx_gmxx_tx_ovr_bp_cn30xx cn50xx; - struct cvmx_gmxx_tx_ovr_bp_s cn52xx; - struct cvmx_gmxx_tx_ovr_bp_s cn52xxp1; - struct cvmx_gmxx_tx_ovr_bp_s cn56xx; - struct cvmx_gmxx_tx_ovr_bp_s cn56xxp1; - struct cvmx_gmxx_tx_ovr_bp_cn38xx cn58xx; - struct cvmx_gmxx_tx_ovr_bp_cn38xx cn58xxp1; -}; - -union cvmx_gmxx_tx_pause_pkt_dmac { - uint64_t u64; - struct cvmx_gmxx_tx_pause_pkt_dmac_s { - uint64_t reserved_48_63:16; - uint64_t dmac:48; - } s; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn30xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn31xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn38xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn38xxp2; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn50xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn52xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn52xxp1; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn56xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn56xxp1; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn58xx; - struct cvmx_gmxx_tx_pause_pkt_dmac_s cn58xxp1; -}; - -union cvmx_gmxx_tx_pause_pkt_type { - uint64_t u64; - struct cvmx_gmxx_tx_pause_pkt_type_s { - uint64_t reserved_16_63:48; - uint64_t type:16; - } s; - struct cvmx_gmxx_tx_pause_pkt_type_s cn30xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn31xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn38xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn38xxp2; - struct cvmx_gmxx_tx_pause_pkt_type_s cn50xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn52xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn52xxp1; - struct cvmx_gmxx_tx_pause_pkt_type_s cn56xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn56xxp1; - struct cvmx_gmxx_tx_pause_pkt_type_s cn58xx; - struct cvmx_gmxx_tx_pause_pkt_type_s cn58xxp1; -}; - -union cvmx_gmxx_tx_prts { - uint64_t u64; - struct cvmx_gmxx_tx_prts_s { - uint64_t reserved_5_63:59; - uint64_t prts:5; - } s; - struct cvmx_gmxx_tx_prts_s cn30xx; - struct cvmx_gmxx_tx_prts_s cn31xx; - struct cvmx_gmxx_tx_prts_s cn38xx; - struct cvmx_gmxx_tx_prts_s cn38xxp2; - struct cvmx_gmxx_tx_prts_s cn50xx; - struct cvmx_gmxx_tx_prts_s cn52xx; - struct cvmx_gmxx_tx_prts_s cn52xxp1; - struct cvmx_gmxx_tx_prts_s cn56xx; - struct cvmx_gmxx_tx_prts_s cn56xxp1; - struct cvmx_gmxx_tx_prts_s cn58xx; - struct cvmx_gmxx_tx_prts_s cn58xxp1; -}; - -union cvmx_gmxx_tx_spi_ctl { - uint64_t u64; - struct cvmx_gmxx_tx_spi_ctl_s { - uint64_t reserved_2_63:62; - uint64_t tpa_clr:1; - uint64_t cont_pkt:1; - } s; - struct cvmx_gmxx_tx_spi_ctl_s cn38xx; - struct cvmx_gmxx_tx_spi_ctl_s cn38xxp2; - struct cvmx_gmxx_tx_spi_ctl_s cn58xx; - struct cvmx_gmxx_tx_spi_ctl_s cn58xxp1; -}; - -union cvmx_gmxx_tx_spi_drain { - uint64_t u64; - struct cvmx_gmxx_tx_spi_drain_s { - uint64_t reserved_16_63:48; - uint64_t drain:16; - } s; - struct cvmx_gmxx_tx_spi_drain_s cn38xx; - struct cvmx_gmxx_tx_spi_drain_s cn58xx; - struct cvmx_gmxx_tx_spi_drain_s cn58xxp1; -}; - -union cvmx_gmxx_tx_spi_max { - uint64_t u64; - struct cvmx_gmxx_tx_spi_max_s { - uint64_t reserved_23_63:41; - uint64_t slice:7; - uint64_t max2:8; - uint64_t max1:8; - } s; - struct cvmx_gmxx_tx_spi_max_cn38xx { - uint64_t reserved_16_63:48; - uint64_t max2:8; - uint64_t max1:8; - } cn38xx; - struct cvmx_gmxx_tx_spi_max_cn38xx cn38xxp2; - struct cvmx_gmxx_tx_spi_max_s cn58xx; - struct cvmx_gmxx_tx_spi_max_s cn58xxp1; -}; - -union cvmx_gmxx_tx_spi_roundx { - uint64_t u64; - struct cvmx_gmxx_tx_spi_roundx_s { - uint64_t reserved_16_63:48; - uint64_t round:16; - } s; - struct cvmx_gmxx_tx_spi_roundx_s cn58xx; - struct cvmx_gmxx_tx_spi_roundx_s cn58xxp1; -}; - -union cvmx_gmxx_tx_spi_thresh { - uint64_t u64; - struct cvmx_gmxx_tx_spi_thresh_s { - uint64_t reserved_6_63:58; - uint64_t thresh:6; - } s; - struct cvmx_gmxx_tx_spi_thresh_s cn38xx; - struct cvmx_gmxx_tx_spi_thresh_s cn38xxp2; - struct cvmx_gmxx_tx_spi_thresh_s cn58xx; - struct cvmx_gmxx_tx_spi_thresh_s cn58xxp1; -}; - -union cvmx_gmxx_tx_xaui_ctl { - uint64_t u64; - struct cvmx_gmxx_tx_xaui_ctl_s { - uint64_t reserved_11_63:53; - uint64_t hg_pause_hgi:2; - uint64_t hg_en:1; - uint64_t reserved_7_7:1; - uint64_t ls_byp:1; - uint64_t ls:2; - uint64_t reserved_2_3:2; - uint64_t uni_en:1; - uint64_t dic_en:1; - } s; - struct cvmx_gmxx_tx_xaui_ctl_s cn52xx; - struct cvmx_gmxx_tx_xaui_ctl_s cn52xxp1; - struct cvmx_gmxx_tx_xaui_ctl_s cn56xx; - struct cvmx_gmxx_tx_xaui_ctl_s cn56xxp1; -}; - -union cvmx_gmxx_xaui_ext_loopback { - uint64_t u64; - struct cvmx_gmxx_xaui_ext_loopback_s { - uint64_t reserved_5_63:59; - uint64_t en:1; - uint64_t thresh:4; - } s; - struct cvmx_gmxx_xaui_ext_loopback_s cn52xx; - struct cvmx_gmxx_xaui_ext_loopback_s cn52xxp1; - struct cvmx_gmxx_xaui_ext_loopback_s cn56xx; - struct cvmx_gmxx_xaui_ext_loopback_s cn56xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-helper-board.c b/drivers/staging/octeon/cvmx-helper-board.c deleted file mode 100644 index 57d35dc63ddb..000000000000 --- a/drivers/staging/octeon/cvmx-helper-board.c +++ /dev/null @@ -1,695 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Helper functions to abstract board specific data about - * network ports from the rest of the cvmx-helper files. - */ - -#include <asm/octeon/octeon.h> -#include <asm/octeon/cvmx-bootinfo.h> - -#include "cvmx-config.h" - -#include "cvmx-mdio.h" - -#include "cvmx-helper.h" -#include "cvmx-helper-util.h" -#include "cvmx-helper-board.h" - -#include "cvmx-gmxx-defs.h" -#include "cvmx-asxx-defs.h" - -/** - * cvmx_override_board_link_get(int ipd_port) is a function - * pointer. It is meant to allow customization of the process of - * talking to a PHY to determine link speed. It is called every - * time a PHY must be polled for link status. Users should set - * this pointer to a function before calling any cvmx-helper - * operations. - */ -cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port) = - NULL; - -/** - * Return the MII PHY address associated with the given IPD - * port. A result of -1 means there isn't a MII capable PHY - * connected to this port. On chips supporting multiple MII - * busses the bus number is encoded in bits <15:8>. - * - * This function must be modified for every new Octeon board. - * Internally it uses switch statements based on the cvmx_sysinfo - * data to determine board types and revisions. It replies on the - * fact that every Octeon board receives a unique board type - * enumeration from the bootloader. - * - * @ipd_port: Octeon IPD port to get the MII address for. - * - * Returns MII PHY address and bus number or -1. - */ -int cvmx_helper_board_get_mii_address(int ipd_port) -{ - switch (cvmx_sysinfo_get()->board_type) { - case CVMX_BOARD_TYPE_SIM: - /* Simulator doesn't have MII */ - return -1; - case CVMX_BOARD_TYPE_EBT3000: - case CVMX_BOARD_TYPE_EBT5800: - case CVMX_BOARD_TYPE_THUNDER: - case CVMX_BOARD_TYPE_NICPRO2: - /* Interface 0 is SPI4, interface 1 is RGMII */ - if ((ipd_port >= 16) && (ipd_port < 20)) - return ipd_port - 16; - else - return -1; - case CVMX_BOARD_TYPE_KODAMA: - case CVMX_BOARD_TYPE_EBH3100: - case CVMX_BOARD_TYPE_HIKARI: - case CVMX_BOARD_TYPE_CN3010_EVB_HS5: - case CVMX_BOARD_TYPE_CN3005_EVB_HS5: - case CVMX_BOARD_TYPE_CN3020_EVB_HS5: - /* - * Port 0 is WAN connected to a PHY, Port 1 is GMII - * connected to a switch - */ - if (ipd_port == 0) - return 4; - else if (ipd_port == 1) - return 9; - else - return -1; - case CVMX_BOARD_TYPE_NAC38: - /* Board has 8 RGMII ports PHYs are 0-7 */ - if ((ipd_port >= 0) && (ipd_port < 4)) - return ipd_port; - else if ((ipd_port >= 16) && (ipd_port < 20)) - return ipd_port - 16 + 4; - else - return -1; - case CVMX_BOARD_TYPE_EBH3000: - /* Board has dual SPI4 and no PHYs */ - return -1; - case CVMX_BOARD_TYPE_EBH5200: - case CVMX_BOARD_TYPE_EBH5201: - case CVMX_BOARD_TYPE_EBT5200: - /* - * Board has 4 SGMII ports. The PHYs start right after the MII - * ports MII0 = 0, MII1 = 1, SGMII = 2-5. - */ - if ((ipd_port >= 0) && (ipd_port < 4)) - return ipd_port + 2; - else - return -1; - case CVMX_BOARD_TYPE_EBH5600: - case CVMX_BOARD_TYPE_EBH5601: - case CVMX_BOARD_TYPE_EBH5610: - /* - * Board has 8 SGMII ports. 4 connect out, two connect - * to a switch, and 2 loop to each other - */ - if ((ipd_port >= 0) && (ipd_port < 4)) - return ipd_port + 1; - else - return -1; - case CVMX_BOARD_TYPE_CUST_NB5: - if (ipd_port == 2) - return 4; - else - return -1; - case CVMX_BOARD_TYPE_NIC_XLE_4G: - /* Board has 4 SGMII ports. connected QLM3(interface 1) */ - if ((ipd_port >= 16) && (ipd_port < 20)) - return ipd_port - 16 + 1; - else - return -1; - case CVMX_BOARD_TYPE_BBGW_REF: - /* - * No PHYs are connected to Octeon, everything is - * through switch. - */ - return -1; - - case CVMX_BOARD_TYPE_CUST_WSX16: - if (ipd_port >= 0 && ipd_port <= 3) - return ipd_port; - else if (ipd_port >= 16 && ipd_port <= 19) - return ipd_port - 16 + 4; - else - return -1; - } - - /* Some unknown board. Somebody forgot to update this function... */ - cvmx_dprintf - ("cvmx_helper_board_get_mii_address: Unknown board type %d\n", - cvmx_sysinfo_get()->board_type); - return -1; -} - -/** - * This function is the board specific method of determining an - * ethernet ports link speed. Most Octeon boards have Marvell PHYs - * and are handled by the fall through case. This function must be - * updated for boards that don't have the normal Marvell PHYs. - * - * This function must be modified for every new Octeon board. - * Internally it uses switch statements based on the cvmx_sysinfo - * data to determine board types and revisions. It relies on the - * fact that every Octeon board receives a unique board type - * enumeration from the bootloader. - * - * @ipd_port: IPD input port associated with the port we want to get link - * status for. - * - * Returns The ports link status. If the link isn't fully resolved, this must - * return zero. - */ -cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) -{ - cvmx_helper_link_info_t result; - int phy_addr; - int is_broadcom_phy = 0; - - /* Give the user a chance to override the processing of this function */ - if (cvmx_override_board_link_get) - return cvmx_override_board_link_get(ipd_port); - - /* Unless we fix it later, all links are defaulted to down */ - result.u64 = 0; - - /* - * This switch statement should handle all ports that either don't use - * Marvell PHYS, or don't support in-band status. - */ - switch (cvmx_sysinfo_get()->board_type) { - case CVMX_BOARD_TYPE_SIM: - /* The simulator gives you a simulated 1Gbps full duplex link */ - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - return result; - case CVMX_BOARD_TYPE_EBH3100: - case CVMX_BOARD_TYPE_CN3010_EVB_HS5: - case CVMX_BOARD_TYPE_CN3005_EVB_HS5: - case CVMX_BOARD_TYPE_CN3020_EVB_HS5: - /* Port 1 on these boards is always Gigabit */ - if (ipd_port == 1) { - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - return result; - } - /* Fall through to the generic code below */ - break; - case CVMX_BOARD_TYPE_CUST_NB5: - /* Port 1 on these boards is always Gigabit */ - if (ipd_port == 1) { - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - return result; - } else /* The other port uses a broadcom PHY */ - is_broadcom_phy = 1; - break; - case CVMX_BOARD_TYPE_BBGW_REF: - /* Port 1 on these boards is always Gigabit */ - if (ipd_port == 2) { - /* Port 2 is not hooked up */ - result.u64 = 0; - return result; - } else { - /* Ports 0 and 1 connect to the switch */ - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - return result; - } - break; - } - - phy_addr = cvmx_helper_board_get_mii_address(ipd_port); - if (phy_addr != -1) { - if (is_broadcom_phy) { - /* - * Below we are going to read SMI/MDIO - * register 0x19 which works on Broadcom - * parts - */ - int phy_status = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - 0x19); - switch ((phy_status >> 8) & 0x7) { - case 0: - result.u64 = 0; - break; - case 1: - result.s.link_up = 1; - result.s.full_duplex = 0; - result.s.speed = 10; - break; - case 2: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 10; - break; - case 3: - result.s.link_up = 1; - result.s.full_duplex = 0; - result.s.speed = 100; - break; - case 4: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 100; - break; - case 5: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 100; - break; - case 6: - result.s.link_up = 1; - result.s.full_duplex = 0; - result.s.speed = 1000; - break; - case 7: - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - break; - } - } else { - /* - * This code assumes we are using a Marvell - * Gigabit PHY. All the speed information can - * be read from register 17 in one - * go. Somebody using a different PHY will - * need to handle it above in the board - * specific area. - */ - int phy_status = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); - - /* - * If the resolve bit 11 isn't set, see if - * autoneg is turned off (bit 12, reg 0). The - * resolve bit doesn't get set properly when - * autoneg is off, so force it. - */ - if ((phy_status & (1 << 11)) == 0) { - int auto_status = - cvmx_mdio_read(phy_addr >> 8, - phy_addr & 0xff, 0); - if ((auto_status & (1 << 12)) == 0) - phy_status |= 1 << 11; - } - - /* - * Only return a link if the PHY has finished - * auto negotiation and set the resolved bit - * (bit 11) - */ - if (phy_status & (1 << 11)) { - result.s.link_up = 1; - result.s.full_duplex = ((phy_status >> 13) & 1); - switch ((phy_status >> 14) & 3) { - case 0: /* 10 Mbps */ - result.s.speed = 10; - break; - case 1: /* 100 Mbps */ - result.s.speed = 100; - break; - case 2: /* 1 Gbps */ - result.s.speed = 1000; - break; - case 3: /* Illegal */ - result.u64 = 0; - break; - } - } - } - } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX) - || OCTEON_IS_MODEL(OCTEON_CN58XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX)) { - /* - * We don't have a PHY address, so attempt to use - * in-band status. It is really important that boards - * not supporting in-band status never get - * here. Reading broken in-band status tends to do bad - * things - */ - union cvmx_gmxx_rxx_rx_inbnd inband_status; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - inband_status.u64 = - cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface)); - - result.s.link_up = inband_status.s.status; - result.s.full_duplex = inband_status.s.duplex; - switch (inband_status.s.speed) { - case 0: /* 10 Mbps */ - result.s.speed = 10; - break; - case 1: /* 100 Mbps */ - result.s.speed = 100; - break; - case 2: /* 1 Gbps */ - result.s.speed = 1000; - break; - case 3: /* Illegal */ - result.u64 = 0; - break; - } - } else { - /* - * We don't have a PHY address and we don't have - * in-band status. There is no way to determine the - * link speed. Return down assuming this port isn't - * wired - */ - result.u64 = 0; - } - - /* If link is down, return all fields as zero. */ - if (!result.s.link_up) - result.u64 = 0; - - return result; -} - -/** - * This function as a board specific method of changing the PHY - * speed, duplex, and auto-negotiation. This programs the PHY and - * not Octeon. This can be used to force Octeon's links to - * specific settings. - * - * @phy_addr: The address of the PHY to program - * @enable_autoneg: - * Non zero if you want to enable auto-negotiation. - * @link_info: Link speed to program. If the speed is zero and auto-negotiation - * is enabled, all possible negotiation speeds are advertised. - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_board_link_set_phy(int phy_addr, - cvmx_helper_board_set_phy_link_flags_types_t - link_flags, - cvmx_helper_link_info_t link_info) -{ - - /* Set the flow control settings based on link_flags */ - if ((link_flags & set_phy_link_flags_flow_control_mask) != - set_phy_link_flags_flow_control_dont_touch) { - cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - reg_autoneg_adver.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER); - reg_autoneg_adver.s.asymmetric_pause = - (link_flags & set_phy_link_flags_flow_control_mask) == - set_phy_link_flags_flow_control_enable; - reg_autoneg_adver.s.pause = - (link_flags & set_phy_link_flags_flow_control_mask) == - set_phy_link_flags_flow_control_enable; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER, - reg_autoneg_adver.u16); - } - - /* If speed isn't set and autoneg is on advertise all supported modes */ - if ((link_flags & set_phy_link_flags_autoneg) - && (link_info.s.speed == 0)) { - cvmx_mdio_phy_reg_control_t reg_control; - cvmx_mdio_phy_reg_status_t reg_status; - cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - cvmx_mdio_phy_reg_extended_status_t reg_extended_status; - cvmx_mdio_phy_reg_control_1000_t reg_control_1000; - - reg_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_STATUS); - reg_autoneg_adver.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER); - reg_autoneg_adver.s.advert_100base_t4 = - reg_status.s.capable_100base_t4; - reg_autoneg_adver.s.advert_10base_tx_full = - reg_status.s.capable_10_full; - reg_autoneg_adver.s.advert_10base_tx_half = - reg_status.s.capable_10_half; - reg_autoneg_adver.s.advert_100base_tx_full = - reg_status.s.capable_100base_x_full; - reg_autoneg_adver.s.advert_100base_tx_half = - reg_status.s.capable_100base_x_half; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER, - reg_autoneg_adver.u16); - if (reg_status.s.capable_extended_status) { - reg_extended_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_EXTENDED_STATUS); - reg_control_1000.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000); - reg_control_1000.s.advert_1000base_t_full = - reg_extended_status.s.capable_1000base_t_full; - reg_control_1000.s.advert_1000base_t_half = - reg_extended_status.s.capable_1000base_t_half; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000, - reg_control_1000.u16); - } - reg_control.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL); - reg_control.s.autoneg_enable = 1; - reg_control.s.restart_autoneg = 1; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); - } else if ((link_flags & set_phy_link_flags_autoneg)) { - cvmx_mdio_phy_reg_control_t reg_control; - cvmx_mdio_phy_reg_status_t reg_status; - cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver; - cvmx_mdio_phy_reg_extended_status_t reg_extended_status; - cvmx_mdio_phy_reg_control_1000_t reg_control_1000; - - reg_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_STATUS); - reg_autoneg_adver.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER); - reg_autoneg_adver.s.advert_100base_t4 = 0; - reg_autoneg_adver.s.advert_10base_tx_full = 0; - reg_autoneg_adver.s.advert_10base_tx_half = 0; - reg_autoneg_adver.s.advert_100base_tx_full = 0; - reg_autoneg_adver.s.advert_100base_tx_half = 0; - if (reg_status.s.capable_extended_status) { - reg_extended_status.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_EXTENDED_STATUS); - reg_control_1000.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000); - reg_control_1000.s.advert_1000base_t_full = 0; - reg_control_1000.s.advert_1000base_t_half = 0; - } - switch (link_info.s.speed) { - case 10: - reg_autoneg_adver.s.advert_10base_tx_full = - link_info.s.full_duplex; - reg_autoneg_adver.s.advert_10base_tx_half = - !link_info.s.full_duplex; - break; - case 100: - reg_autoneg_adver.s.advert_100base_tx_full = - link_info.s.full_duplex; - reg_autoneg_adver.s.advert_100base_tx_half = - !link_info.s.full_duplex; - break; - case 1000: - reg_control_1000.s.advert_1000base_t_full = - link_info.s.full_duplex; - reg_control_1000.s.advert_1000base_t_half = - !link_info.s.full_duplex; - break; - } - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_AUTONEG_ADVER, - reg_autoneg_adver.u16); - if (reg_status.s.capable_extended_status) - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL_1000, - reg_control_1000.u16); - reg_control.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL); - reg_control.s.autoneg_enable = 1; - reg_control.s.restart_autoneg = 1; - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); - } else { - cvmx_mdio_phy_reg_control_t reg_control; - reg_control.u16 = - cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL); - reg_control.s.autoneg_enable = 0; - reg_control.s.restart_autoneg = 1; - reg_control.s.duplex = link_info.s.full_duplex; - if (link_info.s.speed == 1000) { - reg_control.s.speed_msb = 1; - reg_control.s.speed_lsb = 0; - } else if (link_info.s.speed == 100) { - reg_control.s.speed_msb = 0; - reg_control.s.speed_lsb = 1; - } else if (link_info.s.speed == 10) { - reg_control.s.speed_msb = 0; - reg_control.s.speed_lsb = 0; - } - cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff, - CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16); - } - return 0; -} - -/** - * This function is called by cvmx_helper_interface_probe() after it - * determines the number of ports Octeon can support on a specific - * interface. This function is the per board location to override - * this value. It is called with the number of ports Octeon might - * support and should return the number of actual ports on the - * board. - * - * This function must be modifed for every new Octeon board. - * Internally it uses switch statements based on the cvmx_sysinfo - * data to determine board types and revisions. It relys on the - * fact that every Octeon board receives a unique board type - * enumeration from the bootloader. - * - * @interface: Interface to probe - * @supported_ports: - * Number of ports Octeon supports. - * - * Returns Number of ports the actual board supports. Many times this will - * simple be "support_ports". - */ -int __cvmx_helper_board_interface_probe(int interface, int supported_ports) -{ - switch (cvmx_sysinfo_get()->board_type) { - case CVMX_BOARD_TYPE_CN3005_EVB_HS5: - if (interface == 0) - return 2; - break; - case CVMX_BOARD_TYPE_BBGW_REF: - if (interface == 0) - return 2; - break; - case CVMX_BOARD_TYPE_NIC_XLE_4G: - if (interface == 0) - return 0; - break; - /* The 2nd interface on the EBH5600 is connected to the Marvel switch, - which we don't support. Disable ports connected to it */ - case CVMX_BOARD_TYPE_EBH5600: - if (interface == 1) - return 0; - break; - } - return supported_ports; -} - -/** - * Enable packet input/output from the hardware. This function is - * called after by cvmx_helper_packet_hardware_enable() to - * perform board specific initialization. For most boards - * nothing is needed. - * - * @interface: Interface to enable - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_board_hardware_enable(int interface) -{ - if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) { - if (interface == 0) { - /* Different config for switch port */ - cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0); - cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0); - /* - * Boards with gigabit WAN ports need a - * different setting that is compatible with - * 100 Mbit settings - */ - cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface), - 0xc); - cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface), - 0xc); - } - } else if (cvmx_sysinfo_get()->board_type == - CVMX_BOARD_TYPE_CN3010_EVB_HS5) { - /* - * Broadcom PHYs require differnet ASX - * clocks. Unfortunately many boards don't define a - * new board Id and simply mangle the - * CN3010_EVB_HS5 - */ - if (interface == 0) { - /* - * Some boards use a hacked up bootloader that - * identifies them as CN3010_EVB_HS5 - * evaluation boards. This leads to all kinds - * of configuration problems. Detect one - * case, and print warning, while trying to do - * the right thing. - */ - int phy_addr = cvmx_helper_board_get_mii_address(0); - if (phy_addr != -1) { - int phy_identifier = - cvmx_mdio_read(phy_addr >> 8, - phy_addr & 0xff, 0x2); - /* Is it a Broadcom PHY? */ - if (phy_identifier == 0x0143) { - cvmx_dprintf("\n"); - cvmx_dprintf("ERROR:\n"); - cvmx_dprintf - ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n"); - cvmx_dprintf - ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n"); - cvmx_dprintf - ("ERROR: All boards require a unique board type to identify them.\n"); - cvmx_dprintf("ERROR:\n"); - cvmx_dprintf("\n"); - cvmx_wait(1000000000); - cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX - (0, interface), 5); - cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX - (0, interface), 5); - } - } - } - } - return 0; -} diff --git a/drivers/staging/octeon/cvmx-helper-board.h b/drivers/staging/octeon/cvmx-helper-board.h deleted file mode 100644 index b465bec43553..000000000000 --- a/drivers/staging/octeon/cvmx-helper-board.h +++ /dev/null @@ -1,151 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * Helper functions to abstract board specific data about - * network ports from the rest of the cvmx-helper files. - * - */ -#ifndef __CVMX_HELPER_BOARD_H__ -#define __CVMX_HELPER_BOARD_H__ - -#include "cvmx-helper.h" - -typedef enum { - set_phy_link_flags_autoneg = 0x1, - set_phy_link_flags_flow_control_dont_touch = 0x0 << 1, - set_phy_link_flags_flow_control_enable = 0x1 << 1, - set_phy_link_flags_flow_control_disable = 0x2 << 1, - set_phy_link_flags_flow_control_mask = 0x3 << 1, /* Mask for 2 bit wide flow control field */ -} cvmx_helper_board_set_phy_link_flags_types_t; - -/** - * cvmx_override_board_link_get(int ipd_port) is a function - * pointer. It is meant to allow customization of the process of - * talking to a PHY to determine link speed. It is called every - * time a PHY must be polled for link status. Users should set - * this pointer to a function before calling any cvmx-helper - * operations. - */ -extern cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port); - -/** - * Return the MII PHY address associated with the given IPD - * port. A result of -1 means there isn't a MII capable PHY - * connected to this port. On chips supporting multiple MII - * busses the bus number is encoded in bits <15:8>. - * - * This function must be modifed for every new Octeon board. - * Internally it uses switch statements based on the cvmx_sysinfo - * data to determine board types and revisions. It relys on the - * fact that every Octeon board receives a unique board type - * enumeration from the bootloader. - * - * @ipd_port: Octeon IPD port to get the MII address for. - * - * Returns MII PHY address and bus number or -1. - */ -extern int cvmx_helper_board_get_mii_address(int ipd_port); - -/** - * This function as a board specific method of changing the PHY - * speed, duplex, and autonegotiation. This programs the PHY and - * not Octeon. This can be used to force Octeon's links to - * specific settings. - * - * @phy_addr: The address of the PHY to program - * @link_flags: - * Flags to control autonegotiation. Bit 0 is autonegotiation - * enable/disable to maintain backware compatibility. - * @link_info: Link speed to program. If the speed is zero and autonegotiation - * is enabled, all possible negotiation speeds are advertised. - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_board_link_set_phy(int phy_addr, - cvmx_helper_board_set_phy_link_flags_types_t - link_flags, - cvmx_helper_link_info_t link_info); - -/** - * This function is the board specific method of determining an - * ethernet ports link speed. Most Octeon boards have Marvell PHYs - * and are handled by the fall through case. This function must be - * updated for boards that don't have the normal Marvell PHYs. - * - * This function must be modifed for every new Octeon board. - * Internally it uses switch statements based on the cvmx_sysinfo - * data to determine board types and revisions. It relys on the - * fact that every Octeon board receives a unique board type - * enumeration from the bootloader. - * - * @ipd_port: IPD input port associated with the port we want to get link - * status for. - * - * Returns The ports link status. If the link isn't fully resolved, this must - * return zero. - */ -extern cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port); - -/** - * This function is called by cvmx_helper_interface_probe() after it - * determines the number of ports Octeon can support on a specific - * interface. This function is the per board location to override - * this value. It is called with the number of ports Octeon might - * support and should return the number of actual ports on the - * board. - * - * This function must be modifed for every new Octeon board. - * Internally it uses switch statements based on the cvmx_sysinfo - * data to determine board types and revisions. It relys on the - * fact that every Octeon board receives a unique board type - * enumeration from the bootloader. - * - * @interface: Interface to probe - * @supported_ports: - * Number of ports Octeon supports. - * - * Returns Number of ports the actual board supports. Many times this will - * simple be "support_ports". - */ -extern int __cvmx_helper_board_interface_probe(int interface, - int supported_ports); - -/** - * Enable packet input/output from the hardware. This function is - * called after by cvmx_helper_packet_hardware_enable() to - * perform board specific initialization. For most boards - * nothing is needed. - * - * @interface: Interface to enable - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_board_hardware_enable(int interface); - -#endif /* __CVMX_HELPER_BOARD_H__ */ diff --git a/drivers/staging/octeon/cvmx-helper-fpa.c b/drivers/staging/octeon/cvmx-helper-fpa.c deleted file mode 100644 index c239e5f4ab9a..000000000000 --- a/drivers/staging/octeon/cvmx-helper-fpa.c +++ /dev/null @@ -1,243 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Helper functions for FPA setup. - * - */ -#include "executive-config.h" -#include "cvmx-config.h" -#include "cvmx.h" -#include "cvmx-bootmem.h" -#include "cvmx-fpa.h" -#include "cvmx-helper-fpa.h" - -/** - * Allocate memory for and initialize a single FPA pool. - * - * @pool: Pool to initialize - * @buffer_size: Size of buffers to allocate in bytes - * @buffers: Number of buffers to put in the pool. Zero is allowed - * @name: String name of the pool for debugging purposes - * Returns Zero on success, non-zero on failure - */ -static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size, - uint64_t buffers, const char *name) -{ - uint64_t current_num; - void *memory; - uint64_t align = CVMX_CACHE_LINE_SIZE; - - /* - * Align the allocation so that power of 2 size buffers are - * naturally aligned. - */ - while (align < buffer_size) - align = align << 1; - - if (buffers == 0) - return 0; - - current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool)); - if (current_num) { - cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. " - "Skipping setup.\n", - pool, name, (unsigned long long)current_num); - return 0; - } - - memory = cvmx_bootmem_alloc(buffer_size * buffers, align); - if (memory == NULL) { - cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n", - pool, name); - return -1; - } - cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers); - return 0; -} - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Specifying zero for the number of - * buffers will cause that FPA pool to not be setup. This is - * useful if you aren't using some of the hardware and want - * to save memory. Use cvmx_helper_initialize_fpa instead of - * this function directly. - * - * @pip_pool: Should always be CVMX_FPA_PACKET_POOL - * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE - * @pip_buffers: - * Number of packet buffers. - * @wqe_pool: Should always be CVMX_FPA_WQE_POOL - * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE - * @wqe_entries: - * Number of work queue entries - * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL - * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_pool: Should always be CVMX_FPA_TIMER_POOL - * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_pool: Should always be CVMX_FPA_DFA_POOL - * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size, - int pip_buffers, int wqe_pool, - int wqe_size, int wqe_entries, - int pko_pool, int pko_size, - int pko_buffers, int tim_pool, - int tim_size, int tim_buffers, - int dfa_pool, int dfa_size, - int dfa_buffers) -{ - int status; - - cvmx_fpa_enable(); - - if ((pip_buffers > 0) && (pip_buffers <= 64)) - cvmx_dprintf - ("Warning: %d packet buffers may not be enough for hardware" - " prefetch. 65 or more is recommended.\n", pip_buffers); - - if (pip_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size, - pip_buffers, - "Packet Buffers"); - if (status) - return status; - } - - if (wqe_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size, - wqe_entries, - "Work Queue Entries"); - if (status) - return status; - } - - if (pko_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size, - pko_buffers, - "PKO Command Buffers"); - if (status) - return status; - } - - if (tim_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size, - tim_buffers, - "TIM Command Buffers"); - if (status) - return status; - } - - if (dfa_pool >= 0) { - status = - __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size, - dfa_buffers, - "DFA Command Buffers"); - if (status) - return status; - } - - return 0; -} - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Sizes of each element in the pools is - * controlled by the cvmx-config.h header file. Specifying - * zero for any parameter will cause that FPA pool to not be - * setup. This is useful if you aren't using some of the - * hardware and want to save memory. - * - * @packet_buffers: - * Number of packet buffers to allocate - * @work_queue_entries: - * Number of work queue entries - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries, - int pko_buffers, int tim_buffers, - int dfa_buffers) -{ -#ifndef CVMX_FPA_PACKET_POOL -#define CVMX_FPA_PACKET_POOL -1 -#define CVMX_FPA_PACKET_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_WQE_POOL -#define CVMX_FPA_WQE_POOL -1 -#define CVMX_FPA_WQE_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL -#define CVMX_FPA_OUTPUT_BUFFER_POOL -1 -#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_TIMER_POOL -#define CVMX_FPA_TIMER_POOL -1 -#define CVMX_FPA_TIMER_POOL_SIZE 0 -#endif -#ifndef CVMX_FPA_DFA_POOL -#define CVMX_FPA_DFA_POOL -1 -#define CVMX_FPA_DFA_POOL_SIZE 0 -#endif - return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL, - CVMX_FPA_PACKET_POOL_SIZE, - packet_buffers, CVMX_FPA_WQE_POOL, - CVMX_FPA_WQE_POOL_SIZE, - work_queue_entries, - CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, - pko_buffers, CVMX_FPA_TIMER_POOL, - CVMX_FPA_TIMER_POOL_SIZE, - tim_buffers, CVMX_FPA_DFA_POOL, - CVMX_FPA_DFA_POOL_SIZE, - dfa_buffers); -} diff --git a/drivers/staging/octeon/cvmx-helper-fpa.h b/drivers/staging/octeon/cvmx-helper-fpa.h deleted file mode 100644 index 5ff8c93198de..000000000000 --- a/drivers/staging/octeon/cvmx-helper-fpa.h +++ /dev/null @@ -1,64 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Helper functions for FPA setup. - * - */ -#ifndef __CVMX_HELPER_H_FPA__ -#define __CVMX_HELPER_H_FPA__ - -/** - * Allocate memory and initialize the FPA pools using memory - * from cvmx-bootmem. Sizes of each element in the pools is - * controlled by the cvmx-config.h header file. Specifying - * zero for any parameter will cause that FPA pool to not be - * setup. This is useful if you aren't using some of the - * hardware and want to save memory. - * - * @packet_buffers: - * Number of packet buffers to allocate - * @work_queue_entries: - * Number of work queue entries - * @pko_buffers: - * PKO Command buffers. You should at minimum have two per - * each PKO queue. - * @tim_buffers: - * TIM ring buffer command queues. At least two per timer bucket - * is recommened. - * @dfa_buffers: - * DFA command buffer. A relatively small (32 for example) - * number should work. - * Returns Zero on success, non-zero if out of memory - */ -extern int cvmx_helper_initialize_fpa(int packet_buffers, - int work_queue_entries, int pko_buffers, - int tim_buffers, int dfa_buffers); - -#endif /* __CVMX_HELPER_H__ */ diff --git a/drivers/staging/octeon/cvmx-helper-loop.c b/drivers/staging/octeon/cvmx-helper-loop.c deleted file mode 100644 index 55a571a69529..000000000000 --- a/drivers/staging/octeon/cvmx-helper-loop.c +++ /dev/null @@ -1,85 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Functions for LOOP initialization, configuration, - * and monitoring. - */ -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-helper.h" -#include "cvmx-pip-defs.h" - -/** - * Probe a LOOP interface and determine the number of ports - * connected to it. The LOOP interface should still be down - * after this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -int __cvmx_helper_loop_probe(int interface) -{ - union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs; - int num_ports = 4; - int port; - - /* We need to disable length checking so packet < 64 bytes and jumbo - frames don't get errors */ - for (port = 0; port < num_ports; port++) { - union cvmx_pip_prt_cfgx port_cfg; - int ipd_port = cvmx_helper_get_ipd_port(interface, port); - port_cfg.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); - port_cfg.s.maxerr_en = 0; - port_cfg.s.minerr_en = 0; - cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64); - } - - /* Disable FCS stripping for loopback ports */ - ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS); - ipd_sub_port_fcs.s.port_bit2 = 0; - cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64); - return num_ports; -} - -/** - * Bringup and enable a LOOP interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_loop_enable(int interface) -{ - /* Do nothing. */ - return 0; -} diff --git a/drivers/staging/octeon/cvmx-helper-loop.h b/drivers/staging/octeon/cvmx-helper-loop.h deleted file mode 100644 index e646a6ccce75..000000000000 --- a/drivers/staging/octeon/cvmx-helper-loop.h +++ /dev/null @@ -1,59 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, - * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Functions for LOOP initialization, configuration, - * and monitoring. - * - */ -#ifndef __CVMX_HELPER_LOOP_H__ -#define __CVMX_HELPER_LOOP_H__ - -/** - * Probe a LOOP interface and determine the number of ports - * connected to it. The LOOP interface should still be down after - * this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -extern int __cvmx_helper_loop_probe(int interface); - -/** - * Bringup and enable a LOOP interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_loop_enable(int interface); - -#endif diff --git a/drivers/staging/octeon/cvmx-helper-npi.c b/drivers/staging/octeon/cvmx-helper-npi.c deleted file mode 100644 index 7388a1e72b38..000000000000 --- a/drivers/staging/octeon/cvmx-helper-npi.c +++ /dev/null @@ -1,113 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Functions for NPI initialization, configuration, - * and monitoring. - */ -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-helper.h" - -#include "cvmx-pip-defs.h" - -/** - * Probe a NPI interface and determine the number of ports - * connected to it. The NPI interface should still be down - * after this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -int __cvmx_helper_npi_probe(int interface) -{ -#if CVMX_PKO_QUEUES_PER_PORT_PCI > 0 - if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) - return 4; - else if (OCTEON_IS_MODEL(OCTEON_CN56XX) - && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)) - /* The packet engines didn't exist before pass 2 */ - return 4; - else if (OCTEON_IS_MODEL(OCTEON_CN52XX) - && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) - /* The packet engines didn't exist before pass 2 */ - return 4; -#if 0 - /* - * Technically CN30XX, CN31XX, and CN50XX contain packet - * engines, but nobody ever uses them. Since this is the case, - * we disable them here. - */ - else if (OCTEON_IS_MODEL(OCTEON_CN31XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX)) - return 2; - else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) - return 1; -#endif -#endif - return 0; -} - -/** - * Bringup and enable a NPI interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_npi_enable(int interface) -{ - /* - * On CN50XX, CN52XX, and CN56XX we need to disable length - * checking so packet < 64 bytes and jumbo frames don't get - * errors. - */ - if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && - !OCTEON_IS_MODEL(OCTEON_CN58XX)) { - int num_ports = cvmx_helper_ports_on_interface(interface); - int port; - for (port = 0; port < num_ports; port++) { - union cvmx_pip_prt_cfgx port_cfg; - int ipd_port = - cvmx_helper_get_ipd_port(interface, port); - port_cfg.u64 = - cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); - port_cfg.s.maxerr_en = 0; - port_cfg.s.minerr_en = 0; - cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), - port_cfg.u64); - } - } - - /* Enables are controlled by the remote host, so nothing to do here */ - return 0; -} diff --git a/drivers/staging/octeon/cvmx-helper-npi.h b/drivers/staging/octeon/cvmx-helper-npi.h deleted file mode 100644 index 908e7b08c214..000000000000 --- a/drivers/staging/octeon/cvmx-helper-npi.h +++ /dev/null @@ -1,60 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Functions for NPI initialization, configuration, - * and monitoring. - * - */ -#ifndef __CVMX_HELPER_NPI_H__ -#define __CVMX_HELPER_NPI_H__ - -/** - * Probe a NPI interface and determine the number of ports - * connected to it. The NPI interface should still be down after - * this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -extern int __cvmx_helper_npi_probe(int interface); - -/** - * Bringup and enable a NPI interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_npi_enable(int interface); - -#endif diff --git a/drivers/staging/octeon/cvmx-helper-rgmii.c b/drivers/staging/octeon/cvmx-helper-rgmii.c deleted file mode 100644 index aa2d5d7fee2b..000000000000 --- a/drivers/staging/octeon/cvmx-helper-rgmii.c +++ /dev/null @@ -1,525 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Functions for RGMII/GMII/MII initialization, configuration, - * and monitoring. - */ -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - - -#include "cvmx-mdio.h" -#include "cvmx-pko.h" -#include "cvmx-helper.h" -#include "cvmx-helper-board.h" - -#include <asm/octeon/cvmx-npi-defs.h> -#include "cvmx-gmxx-defs.h" -#include "cvmx-asxx-defs.h" -#include "cvmx-dbg-defs.h" - -void __cvmx_interrupt_gmxx_enable(int interface); -void __cvmx_interrupt_asxx_enable(int block); - -/** - * Probe RGMII ports and determine the number present - * - * @interface: Interface to probe - * - * Returns Number of RGMII/GMII/MII ports (0-4). - */ -int __cvmx_helper_rgmii_probe(int interface) -{ - int num_ports = 0; - union cvmx_gmxx_inf_mode mode; - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - - if (mode.s.type) { - if (OCTEON_IS_MODEL(OCTEON_CN38XX) - || OCTEON_IS_MODEL(OCTEON_CN58XX)) { - cvmx_dprintf("ERROR: RGMII initialize called in " - "SPI interface\n"); - } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) - || OCTEON_IS_MODEL(OCTEON_CN30XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX)) { - /* - * On these chips "type" says we're in - * GMII/MII mode. This limits us to 2 ports - */ - num_ports = 2; - } else { - cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", - __func__); - } - } else { - if (OCTEON_IS_MODEL(OCTEON_CN38XX) - || OCTEON_IS_MODEL(OCTEON_CN58XX)) { - num_ports = 4; - } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) - || OCTEON_IS_MODEL(OCTEON_CN30XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX)) { - num_ports = 3; - } else { - cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n", - __func__); - } - } - return num_ports; -} - -/** - * Put an RGMII interface in loopback mode. Internal packets sent - * out will be received back again on the same port. Externally - * received packets will echo back out. - * - * @port: IPD port number to loop. - */ -void cvmx_helper_rgmii_internal_loopback(int port) -{ - int interface = (port >> 4) & 1; - int index = port & 0xf; - uint64_t tmp; - - union cvmx_gmxx_prtx_cfg gmx_cfg; - gmx_cfg.u64 = 0; - gmx_cfg.s.duplex = 1; - gmx_cfg.s.slottime = 1; - gmx_cfg.s.speed = 1; - cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); - tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); - cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp); - tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); - cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp); - tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp); - gmx_cfg.s.en = 1; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); -} - -/** - * Workaround ASX setup errata with CN38XX pass1 - * - * @interface: Interface to setup - * @port: Port to setup (0..3) - * @cpu_clock_hz: - * Chip frequency in Hertz - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_errata_asx_pass1(int interface, int port, - int cpu_clock_hz) -{ - /* Set hi water mark as per errata GMX-4 */ - if (cpu_clock_hz >= 325000000 && cpu_clock_hz < 375000000) - cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 12); - else if (cpu_clock_hz >= 375000000 && cpu_clock_hz < 437000000) - cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 11); - else if (cpu_clock_hz >= 437000000 && cpu_clock_hz < 550000000) - cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 10); - else if (cpu_clock_hz >= 550000000 && cpu_clock_hz < 687000000) - cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 9); - else - cvmx_dprintf("Illegal clock frequency (%d). " - "CVMX_ASXX_TX_HI_WATERX not set\n", cpu_clock_hz); - return 0; -} - -/** - * Configure all of the ASX, GMX, and PKO regsiters required - * to get RGMII to function on the supplied interface. - * - * @interface: PKO Interface to configure (0 or 1) - * - * Returns Zero on success - */ -int __cvmx_helper_rgmii_enable(int interface) -{ - int num_ports = cvmx_helper_ports_on_interface(interface); - int port; - struct cvmx_sysinfo *sys_info_ptr = cvmx_sysinfo_get(); - union cvmx_gmxx_inf_mode mode; - union cvmx_asxx_tx_prt_en asx_tx; - union cvmx_asxx_rx_prt_en asx_rx; - - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - - if (mode.s.en == 0) - return -1; - if ((OCTEON_IS_MODEL(OCTEON_CN38XX) || - OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1) - /* Ignore SPI interfaces */ - return -1; - - /* Configure the ASX registers needed to use the RGMII ports */ - asx_tx.u64 = 0; - asx_tx.s.prt_en = cvmx_build_mask(num_ports); - cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64); - - asx_rx.u64 = 0; - asx_rx.s.prt_en = cvmx_build_mask(num_ports); - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64); - - /* Configure the GMX registers needed to use the RGMII ports */ - for (port = 0; port < num_ports; port++) { - /* Setting of CVMX_GMXX_TXX_THRESH has been moved to - __cvmx_helper_setup_gmx() */ - - if (cvmx_octeon_is_pass1()) - __cvmx_helper_errata_asx_pass1(interface, port, - sys_info_ptr-> - cpu_clock_hz); - else { - /* - * Configure more flexible RGMII preamble - * checking. Pass 1 doesn't support this - * feature. - */ - union cvmx_gmxx_rxx_frm_ctl frm_ctl; - frm_ctl.u64 = - cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL - (port, interface)); - /* New field, so must be compile time */ - frm_ctl.s.pre_free = 1; - cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface), - frm_ctl.u64); - } - - /* - * Each pause frame transmitted will ask for about 10M - * bit times before resume. If buffer space comes - * available before that time has expired, an XON - * pause frame (0 time) will be transmitted to restart - * the flow. - */ - cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface), - 20000); - cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL - (port, interface), 19000); - - if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { - cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), - 16); - cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), - 16); - } else { - cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface), - 24); - cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface), - 24); - } - } - - __cvmx_helper_setup_gmx(interface, num_ports); - - /* enable the ports now */ - for (port = 0; port < num_ports; port++) { - union cvmx_gmxx_prtx_cfg gmx_cfg; - cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port - (interface, port)); - gmx_cfg.u64 = - cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface)); - gmx_cfg.s.en = 1; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface), - gmx_cfg.u64); - } - __cvmx_interrupt_asxx_enable(interface); - __cvmx_interrupt_gmxx_enable(interface); - - return 0; -} - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - union cvmx_asxx_prt_loop asxx_prt_loop; - - asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); - if (asxx_prt_loop.s.int_loop & (1 << index)) { - /* Force 1Gbps full duplex on internal loopback */ - cvmx_helper_link_info_t result; - result.u64 = 0; - result.s.full_duplex = 1; - result.s.link_up = 1; - result.s.speed = 1000; - return result; - } else - return __cvmx_helper_board_link_get(ipd_port); -} - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_rgmii_link_set(int ipd_port, - cvmx_helper_link_info_t link_info) -{ - int result = 0; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - union cvmx_gmxx_prtx_cfg original_gmx_cfg; - union cvmx_gmxx_prtx_cfg new_gmx_cfg; - union cvmx_pko_mem_queue_qos pko_mem_queue_qos; - union cvmx_pko_mem_queue_qos pko_mem_queue_qos_save[16]; - union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp; - union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp_save; - int i; - - /* Ignore speed sets in the simulator */ - if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) - return 0; - - /* Read the current settings so we know the current enable state */ - original_gmx_cfg.u64 = - cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - new_gmx_cfg = original_gmx_cfg; - - /* Disable the lowest level RX */ - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), - cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) & - ~(1 << index)); - - /* Disable all queues so that TX should become idle */ - for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) { - int queue = cvmx_pko_get_base_queue(ipd_port) + i; - cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); - pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS); - pko_mem_queue_qos.s.pid = ipd_port; - pko_mem_queue_qos.s.qid = queue; - pko_mem_queue_qos_save[i] = pko_mem_queue_qos; - pko_mem_queue_qos.s.qos_mask = 0; - cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64); - } - - /* Disable backpressure */ - gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); - gmx_tx_ovr_bp_save = gmx_tx_ovr_bp; - gmx_tx_ovr_bp.s.bp &= ~(1 << index); - gmx_tx_ovr_bp.s.en |= 1 << index; - cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64); - cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface)); - - /* - * Poll the GMX state machine waiting for it to become - * idle. Preferably we should only change speed when it is - * idle. If it doesn't become idle we will still do the speed - * change, but there is a slight chance that GMX will - * lockup. - */ - cvmx_write_csr(CVMX_NPI_DBG_SELECT, - interface * 0x800 + index * 0x100 + 0x880); - CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 7, - ==, 0, 10000); - CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 0xf, - ==, 0, 10000); - - /* Disable the port before we make any changes */ - new_gmx_cfg.s.en = 0; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); - cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - - /* Set full/half duplex */ - if (cvmx_octeon_is_pass1()) - /* Half duplex is broken for 38XX Pass 1 */ - new_gmx_cfg.s.duplex = 1; - else if (!link_info.s.link_up) - /* Force full duplex on down links */ - new_gmx_cfg.s.duplex = 1; - else - new_gmx_cfg.s.duplex = link_info.s.full_duplex; - - /* Set the link speed. Anything unknown is set to 1Gbps */ - if (link_info.s.speed == 10) { - new_gmx_cfg.s.slottime = 0; - new_gmx_cfg.s.speed = 0; - } else if (link_info.s.speed == 100) { - new_gmx_cfg.s.slottime = 0; - new_gmx_cfg.s.speed = 0; - } else { - new_gmx_cfg.s.slottime = 1; - new_gmx_cfg.s.speed = 1; - } - - /* Adjust the clocks */ - if (link_info.s.speed == 10) { - cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50); - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); - } else if (link_info.s.speed == 100) { - cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5); - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); - } else { - cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); - } - - if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) { - if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) { - union cvmx_gmxx_inf_mode mode; - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - - /* - * Port .en .type .p0mii Configuration - * ---- --- ----- ------ ----------------------------------------- - * X 0 X X All links are disabled. - * 0 1 X 0 Port 0 is RGMII - * 0 1 X 1 Port 0 is MII - * 1 1 0 X Ports 1 and 2 are configured as RGMII ports. - * 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or - * MII port is selected by GMX_PRT1_CFG[SPEED]. - */ - - /* In MII mode, CLK_CNT = 1. */ - if (((index == 0) && (mode.s.p0mii == 1)) - || ((index != 0) && (mode.s.type == 1))) { - cvmx_write_csr(CVMX_GMXX_TXX_CLK - (index, interface), 1); - } - } - } - - /* Do a read to make sure all setup stuff is complete */ - cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - - /* Save the new GMX setting without enabling the port */ - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); - - /* Enable the lowest level RX */ - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), - cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1 << - index)); - - /* Re-enable the TX path */ - for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) { - int queue = cvmx_pko_get_base_queue(ipd_port) + i; - cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue); - cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, - pko_mem_queue_qos_save[i].u64); - } - - /* Restore backpressure */ - cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64); - - /* Restore the GMX enable state. Port config is complete */ - new_gmx_cfg.s.en = original_gmx_cfg.s.en; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64); - - return result; -} - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal, - int enable_external) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - int original_enable; - union cvmx_gmxx_prtx_cfg gmx_cfg; - union cvmx_asxx_prt_loop asxx_prt_loop; - - /* Read the current enable state and save it */ - gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - original_enable = gmx_cfg.s.en; - /* Force port to be disabled */ - gmx_cfg.s.en = 0; - if (enable_internal) { - /* Force speed if we're doing internal loopback */ - gmx_cfg.s.duplex = 1; - gmx_cfg.s.slottime = 1; - gmx_cfg.s.speed = 1; - cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1); - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000); - } - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); - - /* Set the loopback bits */ - asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface)); - if (enable_internal) - asxx_prt_loop.s.int_loop |= 1 << index; - else - asxx_prt_loop.s.int_loop &= ~(1 << index); - if (enable_external) - asxx_prt_loop.s.ext_loop |= 1 << index; - else - asxx_prt_loop.s.ext_loop &= ~(1 << index); - cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64); - - /* Force enables in internal loopback */ - if (enable_internal) { - uint64_t tmp; - tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface)); - cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), - (1 << index) | tmp); - tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)); - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), - (1 << index) | tmp); - original_enable = 1; - } - - /* Restore the enable state */ - gmx_cfg.s.en = original_enable; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64); - return 0; -} diff --git a/drivers/staging/octeon/cvmx-helper-rgmii.h b/drivers/staging/octeon/cvmx-helper-rgmii.h deleted file mode 100644 index ea2652604a57..000000000000 --- a/drivers/staging/octeon/cvmx-helper-rgmii.h +++ /dev/null @@ -1,110 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Functions for RGMII/GMII/MII initialization, configuration, - * and monitoring. - * - */ -#ifndef __CVMX_HELPER_RGMII_H__ -#define __CVMX_HELPER_RGMII_H__ - -/** - * Probe RGMII ports and determine the number present - * - * @interface: Interface to probe - * - * Returns Number of RGMII/GMII/MII ports (0-4). - */ -extern int __cvmx_helper_rgmii_probe(int interface); - -/** - * Put an RGMII interface in loopback mode. Internal packets sent - * out will be received back again on the same port. Externally - * received packets will echo back out. - * - * @port: IPD port number to loop. - */ -extern void cvmx_helper_rgmii_internal_loopback(int port); - -/** - * Configure all of the ASX, GMX, and PKO regsiters required - * to get RGMII to function on the supplied interface. - * - * @interface: PKO Interface to configure (0 or 1) - * - * Returns Zero on success - */ -extern int __cvmx_helper_rgmii_enable(int interface); - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -extern cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port); - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_rgmii_link_set(int ipd_port, - cvmx_helper_link_info_t link_info); - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -extern int __cvmx_helper_rgmii_configure_loopback(int ipd_port, - int enable_internal, - int enable_external); - -#endif diff --git a/drivers/staging/octeon/cvmx-helper-sgmii.c b/drivers/staging/octeon/cvmx-helper-sgmii.c deleted file mode 100644 index 6214e3b6d975..000000000000 --- a/drivers/staging/octeon/cvmx-helper-sgmii.c +++ /dev/null @@ -1,550 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Functions for SGMII initialization, configuration, - * and monitoring. - */ - -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-mdio.h" -#include "cvmx-helper.h" -#include "cvmx-helper-board.h" - -#include "cvmx-gmxx-defs.h" -#include "cvmx-pcsx-defs.h" - -void __cvmx_interrupt_gmxx_enable(int interface); -void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); -void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); - -/** - * Perform initialization required only once for an SGMII port. - * - * @interface: Interface to init - * @index: Index of prot on the interface - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index) -{ - const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000; - union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg; - union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg; - union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg; - - /* Disable GMX */ - gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - gmxx_prtx_cfg.s.en = 0; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); - - /* - * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the - * appropriate value. 1000BASE-X specifies a 10ms - * interval. SGMII specifies a 1.6ms interval. - */ - pcs_misc_ctl_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); - pcsx_linkx_timer_count_reg.u64 = - cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface)); - if (pcs_misc_ctl_reg.s.mode) { - /* 1000BASE-X */ - pcsx_linkx_timer_count_reg.s.count = - (10000ull * clock_mhz) >> 10; - } else { - /* SGMII */ - pcsx_linkx_timer_count_reg.s.count = - (1600ull * clock_mhz) >> 10; - } - cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface), - pcsx_linkx_timer_count_reg.u64); - - /* - * Write the advertisement register to be used as the - * tx_Config_Reg<D15:D0> of the autonegotiation. In - * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG. - * In SGMII PHY mode, tx_Config_Reg<D15:D0> is - * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode, - * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this - * step can be skipped. - */ - if (pcs_misc_ctl_reg.s.mode) { - /* 1000BASE-X */ - union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg; - pcsx_anx_adv_reg.u64 = - cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface)); - pcsx_anx_adv_reg.s.rem_flt = 0; - pcsx_anx_adv_reg.s.pause = 3; - pcsx_anx_adv_reg.s.hfd = 1; - pcsx_anx_adv_reg.s.fd = 1; - cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface), - pcsx_anx_adv_reg.u64); - } else { - union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; - pcsx_miscx_ctl_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); - if (pcsx_miscx_ctl_reg.s.mac_phy) { - /* PHY Mode */ - union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg; - pcsx_sgmx_an_adv_reg.u64 = - cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG - (index, interface)); - pcsx_sgmx_an_adv_reg.s.link = 1; - pcsx_sgmx_an_adv_reg.s.dup = 1; - pcsx_sgmx_an_adv_reg.s.speed = 2; - cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG - (index, interface), - pcsx_sgmx_an_adv_reg.u64); - } else { - /* MAC Mode - Nothing to do */ - } - } - return 0; -} - -/** - * Initialize the SERTES link for the first time or after a loss - * of link. - * - * @interface: Interface to init - * @index: Index of prot on the interface - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index) -{ - union cvmx_pcsx_mrx_control_reg control_reg; - - /* - * Take PCS through a reset sequence. - * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero. - * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the - * value of the other PCS*_MR*_CONTROL_REG bits). Read - * PCS*_MR*_CONTROL_REG[RESET] until it changes value to - * zero. - */ - control_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); - if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) { - control_reg.s.reset = 1; - cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), - control_reg.u64); - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_PCSX_MRX_CONTROL_REG(index, interface), - union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) { - cvmx_dprintf("SGMII%d: Timeout waiting for port %d " - "to finish reset\n", - interface, index); - return -1; - } - } - - /* - * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh - * sgmii negotiation starts. - */ - control_reg.s.rst_an = 1; - control_reg.s.an_en = 1; - control_reg.s.pwr_dn = 0; - cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), - control_reg.u64); - - /* - * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating - * that sgmii autonegotiation is complete. In MAC mode this - * isn't an ethernet link, but a link between Octeon and the - * PHY. - */ - if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && - CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface), - union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1, - 10000)) { - /* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */ - return -1; - } - return 0; -} - -/** - * Configure an SGMII link to the specified speed after the SERTES - * link is up. - * - * @interface: Interface to init - * @index: Index of prot on the interface - * @link_info: Link state to configure - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface, - int index, - cvmx_helper_link_info_t - link_info) -{ - int is_enabled; - union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg; - union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; - - /* Disable GMX before we make any changes. Remember the enable state */ - gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - is_enabled = gmxx_prtx_cfg.s.en; - gmxx_prtx_cfg.s.en = 0; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); - - /* Wait for GMX to be idle */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg, - rx_idle, ==, 1, 10000) - || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface), - union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1, - 10000)) { - cvmx_dprintf - ("SGMII%d: Timeout waiting for port %d to be idle\n", - interface, index); - return -1; - } - - /* Read GMX CFG again to make sure the disable completed */ - gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - - /* - * Get the misc control for PCS. We will need to set the - * duplication amount. - */ - pcsx_miscx_ctl_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); - - /* - * Use GMXENO to force the link down if the status we get says - * it should be down. - */ - pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up; - - /* Only change the duplex setting if the link is up */ - if (link_info.s.link_up) - gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex; - - /* Do speed based setting for GMX */ - switch (link_info.s.speed) { - case 10: - gmxx_prtx_cfg.s.speed = 0; - gmxx_prtx_cfg.s.speed_msb = 1; - gmxx_prtx_cfg.s.slottime = 0; - /* Setting from GMX-603 */ - pcsx_miscx_ctl_reg.s.samp_pt = 25; - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); - break; - case 100: - gmxx_prtx_cfg.s.speed = 0; - gmxx_prtx_cfg.s.speed_msb = 0; - gmxx_prtx_cfg.s.slottime = 0; - pcsx_miscx_ctl_reg.s.samp_pt = 0x5; - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0); - break; - case 1000: - gmxx_prtx_cfg.s.speed = 1; - gmxx_prtx_cfg.s.speed_msb = 0; - gmxx_prtx_cfg.s.slottime = 1; - pcsx_miscx_ctl_reg.s.samp_pt = 1; - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192); - break; - default: - break; - } - - /* Write the new misc control for PCS */ - cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), - pcsx_miscx_ctl_reg.u64); - - /* Write the new GMX settings with the port still disabled */ - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); - - /* Read GMX CFG again to make sure the config completed */ - gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - - /* Restore the enabled / disabled state */ - gmxx_prtx_cfg.s.en = is_enabled; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64); - - return 0; -} - -/** - * Bring up the SGMII interface to be ready for packet I/O but - * leave I/O disabled using the GMX override. This function - * follows the bringup documented in 10.6.3 of the manual. - * - * @interface: Interface to bringup - * @num_ports: Number of ports on the interface - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports) -{ - int index; - - __cvmx_helper_setup_gmx(interface, num_ports); - - for (index = 0; index < num_ports; index++) { - int ipd_port = cvmx_helper_get_ipd_port(interface, index); - __cvmx_helper_sgmii_hardware_init_one_time(interface, index); - __cvmx_helper_sgmii_link_set(ipd_port, - __cvmx_helper_sgmii_link_get - (ipd_port)); - - } - - return 0; -} - -/** - * Probe a SGMII interface and determine the number of ports - * connected to it. The SGMII interface should still be down after - * this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -int __cvmx_helper_sgmii_probe(int interface) -{ - union cvmx_gmxx_inf_mode mode; - - /* - * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the - * interface needs to be enabled before IPD otherwise per port - * backpressure may not work properly - */ - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - mode.s.en = 1; - cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); - return 4; -} - -/** - * Bringup and enable a SGMII interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_sgmii_enable(int interface) -{ - int num_ports = cvmx_helper_ports_on_interface(interface); - int index; - - __cvmx_helper_sgmii_hardware_init(interface, num_ports); - - for (index = 0; index < num_ports; index++) { - union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg; - gmxx_prtx_cfg.u64 = - cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface)); - gmxx_prtx_cfg.s.en = 1; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), - gmxx_prtx_cfg.u64); - __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface); - } - __cvmx_interrupt_pcsxx_int_en_reg_enable(interface); - __cvmx_interrupt_gmxx_enable(interface); - return 0; -} - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port) -{ - cvmx_helper_link_info_t result; - union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg; - - result.u64 = 0; - - if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { - /* The simulator gives you a simulated 1Gbps full duplex link */ - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - return result; - } - - pcsx_mrx_control_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); - if (pcsx_mrx_control_reg.s.loopbck1) { - /* Force 1Gbps full duplex link for internal loopback */ - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 1000; - return result; - } - - pcs_misc_ctl_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); - if (pcs_misc_ctl_reg.s.mode) { - /* 1000BASE-X */ - /* FIXME */ - } else { - union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; - pcsx_miscx_ctl_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); - if (pcsx_miscx_ctl_reg.s.mac_phy) { - /* PHY Mode */ - union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg; - union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg; - - /* - * Don't bother continuing if the SERTES low - * level link is down - */ - pcsx_mrx_status_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG - (index, interface)); - if (pcsx_mrx_status_reg.s.lnk_st == 0) { - if (__cvmx_helper_sgmii_hardware_init_link - (interface, index) != 0) - return result; - } - - /* Read the autoneg results */ - pcsx_anx_results_reg.u64 = - cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG - (index, interface)); - if (pcsx_anx_results_reg.s.an_cpt) { - /* - * Auto negotiation is complete. Set - * status accordingly. - */ - result.s.full_duplex = - pcsx_anx_results_reg.s.dup; - result.s.link_up = - pcsx_anx_results_reg.s.link_ok; - switch (pcsx_anx_results_reg.s.spd) { - case 0: - result.s.speed = 10; - break; - case 1: - result.s.speed = 100; - break; - case 2: - result.s.speed = 1000; - break; - default: - result.s.speed = 0; - result.s.link_up = 0; - break; - } - } else { - /* - * Auto negotiation isn't - * complete. Return link down. - */ - result.s.speed = 0; - result.s.link_up = 0; - } - } else { /* MAC Mode */ - - result = __cvmx_helper_board_link_get(ipd_port); - } - } - return result; -} - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_sgmii_link_set(int ipd_port, - cvmx_helper_link_info_t link_info) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - __cvmx_helper_sgmii_hardware_init_link(interface, index); - return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, - link_info); -} - -/** - * Configure a port for internal and/or external loopback. Internal - * loopback causes packets sent by the port to be received by - * Octeon. External loopback causes packets received from the wire to - * sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal, - int enable_external) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg; - union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; - - pcsx_mrx_control_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); - pcsx_mrx_control_reg.s.loopbck1 = enable_internal; - cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), - pcsx_mrx_control_reg.u64); - - pcsx_miscx_ctl_reg.u64 = - cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); - pcsx_miscx_ctl_reg.s.loopbck2 = enable_external; - cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), - pcsx_miscx_ctl_reg.u64); - - __cvmx_helper_sgmii_hardware_init_link(interface, index); - return 0; -} diff --git a/drivers/staging/octeon/cvmx-helper-sgmii.h b/drivers/staging/octeon/cvmx-helper-sgmii.h deleted file mode 100644 index 19b48d60857f..000000000000 --- a/drivers/staging/octeon/cvmx-helper-sgmii.h +++ /dev/null @@ -1,104 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Functions for SGMII initialization, configuration, - * and monitoring. - * - */ -#ifndef __CVMX_HELPER_SGMII_H__ -#define __CVMX_HELPER_SGMII_H__ - -/** - * Probe a SGMII interface and determine the number of ports - * connected to it. The SGMII interface should still be down after - * this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -extern int __cvmx_helper_sgmii_probe(int interface); - -/** - * Bringup and enable a SGMII interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_sgmii_enable(int interface); - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -extern cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port); - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_sgmii_link_set(int ipd_port, - cvmx_helper_link_info_t link_info); - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -extern int __cvmx_helper_sgmii_configure_loopback(int ipd_port, - int enable_internal, - int enable_external); - -#endif diff --git a/drivers/staging/octeon/cvmx-helper-spi.c b/drivers/staging/octeon/cvmx-helper-spi.c deleted file mode 100644 index 8ba6c832471e..000000000000 --- a/drivers/staging/octeon/cvmx-helper-spi.c +++ /dev/null @@ -1,195 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -void __cvmx_interrupt_gmxx_enable(int interface); -void __cvmx_interrupt_spxx_int_msk_enable(int index); -void __cvmx_interrupt_stxx_int_msk_enable(int index); - -/* - * Functions for SPI initialization, configuration, - * and monitoring. - */ -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" -#include "cvmx-spi.h" -#include "cvmx-helper.h" - -#include "cvmx-pip-defs.h" -#include "cvmx-pko-defs.h" - -/* - * CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI - * initialization routines wait for SPI training. You can override the - * value using executive-config.h if necessary. - */ -#ifndef CVMX_HELPER_SPI_TIMEOUT -#define CVMX_HELPER_SPI_TIMEOUT 10 -#endif - -/** - * Probe a SPI interface and determine the number of ports - * connected to it. The SPI interface should still be down after - * this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -int __cvmx_helper_spi_probe(int interface) -{ - int num_ports = 0; - - if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) && - cvmx_spi4000_is_present(interface)) { - num_ports = 10; - } else { - union cvmx_pko_reg_crc_enable enable; - num_ports = 16; - /* - * Unlike the SPI4000, most SPI devices don't - * automatically put on the L2 CRC. For everything - * except for the SPI4000 have PKO append the L2 CRC - * to the packet. - */ - enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE); - enable.s.enable |= 0xffff << (interface * 16); - cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64); - } - __cvmx_helper_setup_gmx(interface, num_ports); - return num_ports; -} - -/** - * Bringup and enable a SPI interface. After this call packet I/O - * should be fully functional. This is called with IPD enabled but - * PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_spi_enable(int interface) -{ - /* - * Normally the ethernet L2 CRC is checked and stripped in the - * GMX block. When you are using SPI, this isn' the case and - * IPD needs to check the L2 CRC. - */ - int num_ports = cvmx_helper_ports_on_interface(interface); - int ipd_port; - for (ipd_port = interface * 16; ipd_port < interface * 16 + num_ports; - ipd_port++) { - union cvmx_pip_prt_cfgx port_config; - port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); - port_config.s.crc_en = 1; - cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_config.u64); - } - - if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) { - cvmx_spi_start_interface(interface, CVMX_SPI_MODE_DUPLEX, - CVMX_HELPER_SPI_TIMEOUT, num_ports); - if (cvmx_spi4000_is_present(interface)) - cvmx_spi4000_initialize(interface); - } - __cvmx_interrupt_spxx_int_msk_enable(interface); - __cvmx_interrupt_stxx_int_msk_enable(interface); - __cvmx_interrupt_gmxx_enable(interface); - return 0; -} - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port) -{ - cvmx_helper_link_info_t result; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - result.u64 = 0; - - if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { - /* The simulator gives you a simulated full duplex link */ - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 10000; - } else if (cvmx_spi4000_is_present(interface)) { - union cvmx_gmxx_rxx_rx_inbnd inband = - cvmx_spi4000_check_speed(interface, index); - result.s.link_up = inband.s.status; - result.s.full_duplex = inband.s.duplex; - switch (inband.s.speed) { - case 0: /* 10 Mbps */ - result.s.speed = 10; - break; - case 1: /* 100 Mbps */ - result.s.speed = 100; - break; - case 2: /* 1 Gbps */ - result.s.speed = 1000; - break; - case 3: /* Illegal */ - result.s.speed = 0; - result.s.link_up = 0; - break; - } - } else { - /* For generic SPI we can't determine the link, just return some - sane results */ - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 10000; - } - return result; -} - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_spi_link_set(int ipd_port, cvmx_helper_link_info_t link_info) -{ - /* Nothing to do. If we have a SPI4000 then the setup was already performed - by cvmx_spi4000_check_speed(). If not then there isn't any link - info */ - return 0; -} diff --git a/drivers/staging/octeon/cvmx-helper-spi.h b/drivers/staging/octeon/cvmx-helper-spi.h deleted file mode 100644 index 69bac036d10e..000000000000 --- a/drivers/staging/octeon/cvmx-helper-spi.h +++ /dev/null @@ -1,84 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Functions for SPI initialization, configuration, - * and monitoring. - */ -#ifndef __CVMX_HELPER_SPI_H__ -#define __CVMX_HELPER_SPI_H__ - -/** - * Probe a SPI interface and determine the number of ports - * connected to it. The SPI interface should still be down after - * this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -extern int __cvmx_helper_spi_probe(int interface); - -/** - * Bringup and enable a SPI interface. After this call packet I/O - * should be fully functional. This is called with IPD enabled but - * PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_spi_enable(int interface); - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -extern cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port); - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_spi_link_set(int ipd_port, - cvmx_helper_link_info_t link_info); - -#endif diff --git a/drivers/staging/octeon/cvmx-helper-util.c b/drivers/staging/octeon/cvmx-helper-util.c deleted file mode 100644 index 131182bf5abb..000000000000 --- a/drivers/staging/octeon/cvmx-helper-util.c +++ /dev/null @@ -1,433 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Small helper utilities. - */ -#include <linux/kernel.h> - -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-fpa.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-ipd.h" -#include "cvmx-spi.h" - -#include "cvmx-helper.h" -#include "cvmx-helper-util.h" - -#include <asm/octeon/cvmx-ipd-defs.h> - -/** - * Convert a interface mode into a human readable string - * - * @mode: Mode to convert - * - * Returns String - */ -const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t - mode) -{ - switch (mode) { - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - return "DISABLED"; - case CVMX_HELPER_INTERFACE_MODE_RGMII: - return "RGMII"; - case CVMX_HELPER_INTERFACE_MODE_GMII: - return "GMII"; - case CVMX_HELPER_INTERFACE_MODE_SPI: - return "SPI"; - case CVMX_HELPER_INTERFACE_MODE_PCIE: - return "PCIE"; - case CVMX_HELPER_INTERFACE_MODE_XAUI: - return "XAUI"; - case CVMX_HELPER_INTERFACE_MODE_SGMII: - return "SGMII"; - case CVMX_HELPER_INTERFACE_MODE_PICMG: - return "PICMG"; - case CVMX_HELPER_INTERFACE_MODE_NPI: - return "NPI"; - case CVMX_HELPER_INTERFACE_MODE_LOOP: - return "LOOP"; - } - return "UNKNOWN"; -} - -/** - * Debug routine to dump the packet structure to the console - * - * @work: Work queue entry containing the packet to dump - * Returns - */ -int cvmx_helper_dump_packet(cvmx_wqe_t *work) -{ - uint64_t count; - uint64_t remaining_bytes; - union cvmx_buf_ptr buffer_ptr; - uint64_t start_of_buffer; - uint8_t *data_address; - uint8_t *end_of_data; - - cvmx_dprintf("Packet Length: %u\n", work->len); - cvmx_dprintf(" Input Port: %u\n", work->ipprt); - cvmx_dprintf(" QoS: %u\n", work->qos); - cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); - - if (work->word2.s.bufs == 0) { - union cvmx_ipd_wqe_fpa_queue wqe_pool; - wqe_pool.u64 = cvmx_read_csr(CVMX_IPD_WQE_FPA_QUEUE); - buffer_ptr.u64 = 0; - buffer_ptr.s.pool = wqe_pool.s.wqe_pool; - buffer_ptr.s.size = 128; - buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data); - if (likely(!work->word2.s.not_IP)) { - union cvmx_pip_ip_offset pip_ip_offset; - pip_ip_offset.u64 = cvmx_read_csr(CVMX_PIP_IP_OFFSET); - buffer_ptr.s.addr += - (pip_ip_offset.s.offset << 3) - - work->word2.s.ip_offset; - buffer_ptr.s.addr += (work->word2.s.is_v6 ^ 1) << 2; - } else { - /* - * WARNING: This code assumes that the packet - * is not RAW. If it was, we would use - * PIP_GBL_CFG[RAW_SHF] instead of - * PIP_GBL_CFG[NIP_SHF]. - */ - union cvmx_pip_gbl_cfg pip_gbl_cfg; - pip_gbl_cfg.u64 = cvmx_read_csr(CVMX_PIP_GBL_CFG); - buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf; - } - } else - buffer_ptr = work->packet_ptr; - remaining_bytes = work->len; - - while (remaining_bytes) { - start_of_buffer = - ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; - cvmx_dprintf(" Buffer Start:%llx\n", - (unsigned long long)start_of_buffer); - cvmx_dprintf(" Buffer I : %u\n", buffer_ptr.s.i); - cvmx_dprintf(" Buffer Back: %u\n", buffer_ptr.s.back); - cvmx_dprintf(" Buffer Pool: %u\n", buffer_ptr.s.pool); - cvmx_dprintf(" Buffer Data: %llx\n", - (unsigned long long)buffer_ptr.s.addr); - cvmx_dprintf(" Buffer Size: %u\n", buffer_ptr.s.size); - - cvmx_dprintf("\t\t"); - data_address = (uint8_t *) cvmx_phys_to_ptr(buffer_ptr.s.addr); - end_of_data = data_address + buffer_ptr.s.size; - count = 0; - while (data_address < end_of_data) { - if (remaining_bytes == 0) - break; - else - remaining_bytes--; - cvmx_dprintf("%02x", (unsigned int)*data_address); - data_address++; - if (remaining_bytes && (count == 7)) { - cvmx_dprintf("\n\t\t"); - count = 0; - } else - count++; - } - cvmx_dprintf("\n"); - - if (remaining_bytes) - buffer_ptr = *(union cvmx_buf_ptr *) - cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); - } - return 0; -} - -/** - * Setup Random Early Drop on a specific input queue - * - * @queue: Input queue to setup RED on (0-7) - * @pass_thresh: - * Packets will begin slowly dropping when there are less than - * this many packet buffers free in FPA 0. - * @drop_thresh: - * All incomming packets will be dropped when there are less - * than this many free packet buffers in FPA 0. - * Returns Zero on success. Negative on failure - */ -int cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh) -{ - union cvmx_ipd_qosx_red_marks red_marks; - union cvmx_ipd_red_quex_param red_param; - - /* Set RED to begin dropping packets when there are pass_thresh buffers - left. It will linearly drop more packets until reaching drop_thresh - buffers */ - red_marks.u64 = 0; - red_marks.s.drop = drop_thresh; - red_marks.s.pass = pass_thresh; - cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64); - - /* Use the actual queue 0 counter, not the average */ - red_param.u64 = 0; - red_param.s.prb_con = - (255ul << 24) / (red_marks.s.pass - red_marks.s.drop); - red_param.s.avg_con = 1; - red_param.s.new_con = 255; - red_param.s.use_pcnt = 1; - cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64); - return 0; -} - -/** - * Setup Random Early Drop to automatically begin dropping packets. - * - * @pass_thresh: - * Packets will begin slowly dropping when there are less than - * this many packet buffers free in FPA 0. - * @drop_thresh: - * All incomming packets will be dropped when there are less - * than this many free packet buffers in FPA 0. - * Returns Zero on success. Negative on failure - */ -int cvmx_helper_setup_red(int pass_thresh, int drop_thresh) -{ - union cvmx_ipd_portx_bp_page_cnt page_cnt; - union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end; - union cvmx_ipd_red_port_enable red_port_enable; - int queue; - int interface; - int port; - - /* Disable backpressure based on queued buffers. It needs SW support */ - page_cnt.u64 = 0; - page_cnt.s.bp_enb = 0; - page_cnt.s.page_cnt = 100; - for (interface = 0; interface < 2; interface++) { - for (port = cvmx_helper_get_first_ipd_port(interface); - port < cvmx_helper_get_last_ipd_port(interface); port++) - cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port), - page_cnt.u64); - } - - for (queue = 0; queue < 8; queue++) - cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh); - - /* Shutoff the dropping based on the per port page count. SW isn't - decrementing it right now */ - ipd_bp_prt_red_end.u64 = 0; - ipd_bp_prt_red_end.s.prt_enb = 0; - cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64); - - red_port_enable.u64 = 0; - red_port_enable.s.prt_enb = 0xfffffffffull; - red_port_enable.s.avg_dly = 10000; - red_port_enable.s.prb_dly = 10000; - cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64); - - return 0; -} - -/** - * Setup the common GMX settings that determine the number of - * ports. These setting apply to almost all configurations of all - * chips. - * - * @interface: Interface to configure - * @num_ports: Number of ports on the interface - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_setup_gmx(int interface, int num_ports) -{ - union cvmx_gmxx_tx_prts gmx_tx_prts; - union cvmx_gmxx_rx_prts gmx_rx_prts; - union cvmx_pko_reg_gmx_port_mode pko_mode; - union cvmx_gmxx_txx_thresh gmx_tx_thresh; - int index; - - /* Tell GMX the number of TX ports on this interface */ - gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface)); - gmx_tx_prts.s.prts = num_ports; - cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64); - - /* Tell GMX the number of RX ports on this interface. This only - ** applies to *GMII and XAUI ports */ - if (cvmx_helper_interface_get_mode(interface) == - CVMX_HELPER_INTERFACE_MODE_RGMII - || cvmx_helper_interface_get_mode(interface) == - CVMX_HELPER_INTERFACE_MODE_SGMII - || cvmx_helper_interface_get_mode(interface) == - CVMX_HELPER_INTERFACE_MODE_GMII - || cvmx_helper_interface_get_mode(interface) == - CVMX_HELPER_INTERFACE_MODE_XAUI) { - if (num_ports > 4) { - cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal " - "num_ports\n"); - return -1; - } - - gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface)); - gmx_rx_prts.s.prts = num_ports; - cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64); - } - - /* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */ - if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX) - && !OCTEON_IS_MODEL(OCTEON_CN50XX)) { - /* Tell PKO the number of ports on this interface */ - pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE); - if (interface == 0) { - if (num_ports == 1) - pko_mode.s.mode0 = 4; - else if (num_ports == 2) - pko_mode.s.mode0 = 3; - else if (num_ports <= 4) - pko_mode.s.mode0 = 2; - else if (num_ports <= 8) - pko_mode.s.mode0 = 1; - else - pko_mode.s.mode0 = 0; - } else { - if (num_ports == 1) - pko_mode.s.mode1 = 4; - else if (num_ports == 2) - pko_mode.s.mode1 = 3; - else if (num_ports <= 4) - pko_mode.s.mode1 = 2; - else if (num_ports <= 8) - pko_mode.s.mode1 = 1; - else - pko_mode.s.mode1 = 0; - } - cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64); - } - - /* - * Set GMX to buffer as much data as possible before starting - * transmit. This reduces the chances that we have a TX under - * run due to memory contention. Any packet that fits entirely - * in the GMX FIFO can never have an under run regardless of - * memory load. - */ - gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface)); - if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX)) { - /* These chips have a fixed max threshold of 0x40 */ - gmx_tx_thresh.s.cnt = 0x40; - } else { - /* Choose the max value for the number of ports */ - if (num_ports <= 1) - gmx_tx_thresh.s.cnt = 0x100 / 1; - else if (num_ports == 2) - gmx_tx_thresh.s.cnt = 0x100 / 2; - else - gmx_tx_thresh.s.cnt = 0x100 / 4; - } - /* - * SPI and XAUI can have lots of ports but the GMX hardware - * only ever has a max of 4. - */ - if (num_ports > 4) - num_ports = 4; - for (index = 0; index < num_ports; index++) - cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface), - gmx_tx_thresh.u64); - - return 0; -} - -/** - * Returns the IPD/PKO port number for a port on the given - * interface. - * - * @interface: Interface to use - * @port: Port on the interface - * - * Returns IPD/PKO port number - */ -int cvmx_helper_get_ipd_port(int interface, int port) -{ - switch (interface) { - case 0: - return port; - case 1: - return port + 16; - case 2: - return port + 32; - case 3: - return port + 36; - } - return -1; -} - -/** - * Returns the interface number for an IPD/PKO port number. - * - * @ipd_port: IPD/PKO port number - * - * Returns Interface number - */ -int cvmx_helper_get_interface_num(int ipd_port) -{ - if (ipd_port < 16) - return 0; - else if (ipd_port < 32) - return 1; - else if (ipd_port < 36) - return 2; - else if (ipd_port < 40) - return 3; - else - cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " - "port number\n"); - - return -1; -} - -/** - * Returns the interface index number for an IPD/PKO port - * number. - * - * @ipd_port: IPD/PKO port number - * - * Returns Interface index number - */ -int cvmx_helper_get_interface_index_num(int ipd_port) -{ - if (ipd_port < 32) - return ipd_port & 15; - else if (ipd_port < 36) - return ipd_port & 3; - else if (ipd_port < 40) - return ipd_port & 3; - else - cvmx_dprintf("cvmx_helper_get_interface_index_num: " - "Illegal IPD port number\n"); - - return -1; -} diff --git a/drivers/staging/octeon/cvmx-helper-util.h b/drivers/staging/octeon/cvmx-helper-util.h deleted file mode 100644 index 6a6e52fc22c1..000000000000 --- a/drivers/staging/octeon/cvmx-helper-util.h +++ /dev/null @@ -1,215 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Small helper utilities. - * - */ - -#ifndef __CVMX_HELPER_UTIL_H__ -#define __CVMX_HELPER_UTIL_H__ - -/** - * Convert a interface mode into a human readable string - * - * @mode: Mode to convert - * - * Returns String - */ -extern const char - *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode); - -/** - * Debug routine to dump the packet structure to the console - * - * @work: Work queue entry containing the packet to dump - * Returns - */ -extern int cvmx_helper_dump_packet(cvmx_wqe_t *work); - -/** - * Setup Random Early Drop on a specific input queue - * - * @queue: Input queue to setup RED on (0-7) - * @pass_thresh: - * Packets will begin slowly dropping when there are less than - * this many packet buffers free in FPA 0. - * @drop_thresh: - * All incomming packets will be dropped when there are less - * than this many free packet buffers in FPA 0. - * Returns Zero on success. Negative on failure - */ -extern int cvmx_helper_setup_red_queue(int queue, int pass_thresh, - int drop_thresh); - -/** - * Setup Random Early Drop to automatically begin dropping packets. - * - * @pass_thresh: - * Packets will begin slowly dropping when there are less than - * this many packet buffers free in FPA 0. - * @drop_thresh: - * All incomming packets will be dropped when there are less - * than this many free packet buffers in FPA 0. - * Returns Zero on success. Negative on failure - */ -extern int cvmx_helper_setup_red(int pass_thresh, int drop_thresh); - -/** - * Get the version of the CVMX libraries. - * - * Returns Version string. Note this buffer is allocated statically - * and will be shared by all callers. - */ -extern const char *cvmx_helper_get_version(void); - -/** - * Setup the common GMX settings that determine the number of - * ports. These setting apply to almost all configurations of all - * chips. - * - * @interface: Interface to configure - * @num_ports: Number of ports on the interface - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_setup_gmx(int interface, int num_ports); - -/** - * Returns the IPD/PKO port number for a port on the given - * interface. - * - * @interface: Interface to use - * @port: Port on the interface - * - * Returns IPD/PKO port number - */ -extern int cvmx_helper_get_ipd_port(int interface, int port); - -/** - * Returns the IPD/PKO port number for the first port on the given - * interface. - * - * @interface: Interface to use - * - * Returns IPD/PKO port number - */ -static inline int cvmx_helper_get_first_ipd_port(int interface) -{ - return cvmx_helper_get_ipd_port(interface, 0); -} - -/** - * Returns the IPD/PKO port number for the last port on the given - * interface. - * - * @interface: Interface to use - * - * Returns IPD/PKO port number - */ -static inline int cvmx_helper_get_last_ipd_port(int interface) -{ - extern int cvmx_helper_ports_on_interface(int interface); - - return cvmx_helper_get_first_ipd_port(interface) + - cvmx_helper_ports_on_interface(interface) - 1; -} - -/** - * Free the packet buffers contained in a work queue entry. - * The work queue entry is not freed. - * - * @work: Work queue entry with packet to free - */ -static inline void cvmx_helper_free_packet_data(cvmx_wqe_t *work) -{ - uint64_t number_buffers; - union cvmx_buf_ptr buffer_ptr; - union cvmx_buf_ptr next_buffer_ptr; - uint64_t start_of_buffer; - - number_buffers = work->word2.s.bufs; - if (number_buffers == 0) - return; - buffer_ptr = work->packet_ptr; - - /* - * Since the number of buffers is not zero, we know this is - * not a dynamic short packet. We need to check if it is a - * packet received with IPD_CTL_STATUS[NO_WPTR]. If this is - * true, we need to free all buffers except for the first - * one. The caller doesn't expect their WQE pointer to be - * freed - */ - start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; - if (cvmx_ptr_to_phys(work) == start_of_buffer) { - next_buffer_ptr = - *(union cvmx_buf_ptr *) cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); - buffer_ptr = next_buffer_ptr; - number_buffers--; - } - - while (number_buffers--) { - /* - * Remember the back pointer is in cache lines, not - * 64bit words - */ - start_of_buffer = - ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; - /* - * Read pointer to next buffer before we free the - * current buffer. - */ - next_buffer_ptr = - *(union cvmx_buf_ptr *) cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); - cvmx_fpa_free(cvmx_phys_to_ptr(start_of_buffer), - buffer_ptr.s.pool, 0); - buffer_ptr = next_buffer_ptr; - } -} - -/** - * Returns the interface number for an IPD/PKO port number. - * - * @ipd_port: IPD/PKO port number - * - * Returns Interface number - */ -extern int cvmx_helper_get_interface_num(int ipd_port); - -/** - * Returns the interface index number for an IPD/PKO port - * number. - * - * @ipd_port: IPD/PKO port number - * - * Returns Interface index number - */ -extern int cvmx_helper_get_interface_index_num(int ipd_port); - -#endif /* __CVMX_HELPER_H__ */ diff --git a/drivers/staging/octeon/cvmx-helper-xaui.c b/drivers/staging/octeon/cvmx-helper-xaui.c deleted file mode 100644 index a11e6769e234..000000000000 --- a/drivers/staging/octeon/cvmx-helper-xaui.c +++ /dev/null @@ -1,348 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Functions for XAUI initialization, configuration, - * and monitoring. - * - */ - -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-helper.h" - -#include "cvmx-pko-defs.h" -#include "cvmx-gmxx-defs.h" -#include "cvmx-pcsxx-defs.h" - -void __cvmx_interrupt_gmxx_enable(int interface); -void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block); -void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index); -/** - * Probe a XAUI interface and determine the number of ports - * connected to it. The XAUI interface should still be down - * after this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -int __cvmx_helper_xaui_probe(int interface) -{ - int i; - union cvmx_gmxx_hg2_control gmx_hg2_control; - union cvmx_gmxx_inf_mode mode; - - /* - * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the - * interface needs to be enabled before IPD otherwise per port - * backpressure may not work properly. - */ - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - mode.s.en = 1; - cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64); - - __cvmx_helper_setup_gmx(interface, 1); - - /* - * Setup PKO to support 16 ports for HiGig2 virtual - * ports. We're pointing all of the PKO packet ports for this - * interface to the XAUI. This allows us to use HiGig2 - * backpressure per port. - */ - for (i = 0; i < 16; i++) { - union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs; - pko_mem_port_ptrs.u64 = 0; - /* - * We set each PKO port to have equal priority in a - * round robin fashion. - */ - pko_mem_port_ptrs.s.static_p = 0; - pko_mem_port_ptrs.s.qos_mask = 0xff; - /* All PKO ports map to the same XAUI hardware port */ - pko_mem_port_ptrs.s.eid = interface * 4; - pko_mem_port_ptrs.s.pid = interface * 16 + i; - cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64); - } - - /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */ - gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface)); - if (gmx_hg2_control.s.hg2tx_en) - return 16; - else - return 1; -} - -/** - * Bringup and enable a XAUI interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_xaui_enable(int interface) -{ - union cvmx_gmxx_prtx_cfg gmx_cfg; - union cvmx_pcsxx_control1_reg xauiCtl; - union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl; - union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl; - union cvmx_gmxx_rxx_int_en gmx_rx_int_en; - union cvmx_gmxx_tx_int_en gmx_tx_int_en; - union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; - - /* (1) Interface has already been enabled. */ - - /* (2) Disable GMX. */ - xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface)); - xauiMiscCtl.s.gmxeno = 1; - cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); - - /* (3) Disable GMX and PCSX interrupts. */ - gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface)); - cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); - gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface)); - cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); - pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface)); - cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); - - /* (4) Bring up the PCSX and GMX reconciliation layer. */ - /* (4)a Set polarity and lane swapping. */ - /* (4)b */ - gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); - /* Enable better IFG packing and improves performance */ - gmxXauiTxCtl.s.dic_en = 1; - gmxXauiTxCtl.s.uni_en = 0; - cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64); - - /* (4)c Aply reset sequence */ - xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); - xauiCtl.s.lo_pwr = 0; - xauiCtl.s.reset = 1; - cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); - - /* Wait for PCS to come out of reset */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg, - reset, ==, 0, 10000)) - return -1; - /* Wait for PCS to be aligned */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_PCSXX_10GBX_STATUS_REG(interface), - union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000)) - return -1; - /* Wait for RX to be ready */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl, - status, ==, 0, 10000)) - return -1; - - /* (6) Configure GMX */ - gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); - gmx_cfg.s.en = 0; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); - - /* Wait for GMX RX to be idle */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, - rx_idle, ==, 1, 10000)) - return -1; - /* Wait for GMX TX to be idle */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg, - tx_idle, ==, 1, 10000)) - return -1; - - /* GMX configure */ - gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); - gmx_cfg.s.speed = 1; - gmx_cfg.s.speed_msb = 0; - gmx_cfg.s.slottime = 1; - cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1); - cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512); - cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192); - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); - - /* (7) Clear out any error state */ - cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface), - cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface))); - cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface), - cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface))); - cvmx_write_csr(CVMX_PCSXX_INT_REG(interface), - cvmx_read_csr(CVMX_PCSXX_INT_REG(interface))); - - /* Wait for receive link */ - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg, - rcv_lnk, ==, 1, 10000)) - return -1; - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, - xmtflt, ==, 0, 10000)) - return -1; - if (CVMX_WAIT_FOR_FIELD64 - (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg, - rcvflt, ==, 0, 10000)) - return -1; - - cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64); - cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); - cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64); - - cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0)); - - /* (8) Enable packet reception */ - xauiMiscCtl.s.gmxeno = 0; - cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64); - - gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); - gmx_cfg.s.en = 1; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); - - __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface); - __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface); - __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface); - __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface); - __cvmx_interrupt_pcsxx_int_en_reg_enable(interface); - __cvmx_interrupt_gmxx_enable(interface); - - return 0; -} - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; - union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; - union cvmx_pcsxx_status1_reg pcsxx_status1_reg; - cvmx_helper_link_info_t result; - - gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); - gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); - pcsxx_status1_reg.u64 = - cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface)); - result.u64 = 0; - - /* Only return a link if both RX and TX are happy */ - if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) && - (pcsxx_status1_reg.s.rcv_lnk == 1)) { - result.s.link_up = 1; - result.s.full_duplex = 1; - result.s.speed = 10000; - } else { - /* Disable GMX and PCSX interrupts. */ - cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0); - cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0); - cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0); - } - return result; -} - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl; - union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl; - - gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface)); - gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface)); - - /* If the link shouldn't be up, then just return */ - if (!link_info.s.link_up) - return 0; - - /* Do nothing if both RX and TX are happy */ - if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0)) - return 0; - - /* Bring the link up */ - return __cvmx_helper_xaui_enable(interface); -} - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, - int enable_internal, - int enable_external) -{ - int interface = cvmx_helper_get_interface_num(ipd_port); - union cvmx_pcsxx_control1_reg pcsxx_control1_reg; - union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback; - - /* Set the internal loop */ - pcsxx_control1_reg.u64 = - cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); - pcsxx_control1_reg.s.loopbck1 = enable_internal; - cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), - pcsxx_control1_reg.u64); - - /* Set the external loop */ - gmxx_xaui_ext_loopback.u64 = - cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface)); - gmxx_xaui_ext_loopback.s.en = enable_external; - cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface), - gmxx_xaui_ext_loopback.u64); - - /* Take the link through a reset */ - return __cvmx_helper_xaui_enable(interface); -} diff --git a/drivers/staging/octeon/cvmx-helper-xaui.h b/drivers/staging/octeon/cvmx-helper-xaui.h deleted file mode 100644 index 4b4db2f93cd4..000000000000 --- a/drivers/staging/octeon/cvmx-helper-xaui.h +++ /dev/null @@ -1,103 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * @file - * - * Functions for XAUI initialization, configuration, - * and monitoring. - * - */ -#ifndef __CVMX_HELPER_XAUI_H__ -#define __CVMX_HELPER_XAUI_H__ - -/** - * Probe a XAUI interface and determine the number of ports - * connected to it. The XAUI interface should still be down - * after this call. - * - * @interface: Interface to probe - * - * Returns Number of ports on the interface. Zero to disable. - */ -extern int __cvmx_helper_xaui_probe(int interface); - -/** - * Bringup and enable a XAUI interface. After this call packet - * I/O should be fully functional. This is called with IPD - * enabled but PKO disabled. - * - * @interface: Interface to bring up - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_xaui_enable(int interface); - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -extern cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port); - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -extern int __cvmx_helper_xaui_link_set(int ipd_port, - cvmx_helper_link_info_t link_info); - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -extern int __cvmx_helper_xaui_configure_loopback(int ipd_port, - int enable_internal, - int enable_external); -#endif diff --git a/drivers/staging/octeon/cvmx-helper.c b/drivers/staging/octeon/cvmx-helper.c deleted file mode 100644 index e9c5c836ceff..000000000000 --- a/drivers/staging/octeon/cvmx-helper.c +++ /dev/null @@ -1,1058 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Helper functions for common, but complicated tasks. - * - */ -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-fpa.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-ipd.h" -#include "cvmx-spi.h" -#include "cvmx-helper.h" -#include "cvmx-helper-board.h" - -#include "cvmx-pip-defs.h" -#include "cvmx-smix-defs.h" -#include "cvmx-asxx-defs.h" - -/** - * cvmx_override_pko_queue_priority(int ipd_port, uint64_t - * priorities[16]) is a function pointer. It is meant to allow - * customization of the PKO queue priorities based on the port - * number. Users should set this pointer to a function before - * calling any cvmx-helper operations. - */ -void (*cvmx_override_pko_queue_priority) (int pko_port, - uint64_t priorities[16]); - -/** - * cvmx_override_ipd_port_setup(int ipd_port) is a function - * pointer. It is meant to allow customization of the IPD port - * setup before packet input/output comes online. It is called - * after cvmx-helper does the default IPD configuration, but - * before IPD is enabled. Users should set this pointer to a - * function before calling any cvmx-helper operations. - */ -void (*cvmx_override_ipd_port_setup) (int ipd_port); - -/* Port count per interface */ -static int interface_port_count[4] = { 0, 0, 0, 0 }; - -/* Port last configured link info index by IPD/PKO port */ -static cvmx_helper_link_info_t - port_link_info[CVMX_PIP_NUM_INPUT_PORTS]; - -/** - * Return the number of interfaces the chip has. Each interface - * may have multiple ports. Most chips support two interfaces, - * but the CNX0XX and CNX1XX are exceptions. These only support - * one interface. - * - * Returns Number of interfaces on chip - */ -int cvmx_helper_get_number_of_interfaces(void) -{ - if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) - return 4; - else - return 3; -} - -/** - * Return the number of ports on an interface. Depending on the - * chip and configuration, this can be 1-16. A value of 0 - * specifies that the interface doesn't exist or isn't usable. - * - * @interface: Interface to get the port count for - * - * Returns Number of ports on interface. Can be Zero. - */ -int cvmx_helper_ports_on_interface(int interface) -{ - return interface_port_count[interface]; -} - -/** - * Get the operating mode of an interface. Depending on the Octeon - * chip and configuration, this function returns an enumeration - * of the type of packet I/O supported by an interface. - * - * @interface: Interface to probe - * - * Returns Mode of the interface. Unknown or unsupported interfaces return - * DISABLED. - */ -cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface) -{ - union cvmx_gmxx_inf_mode mode; - if (interface == 2) - return CVMX_HELPER_INTERFACE_MODE_NPI; - - if (interface == 3) { - if (OCTEON_IS_MODEL(OCTEON_CN56XX) - || OCTEON_IS_MODEL(OCTEON_CN52XX)) - return CVMX_HELPER_INTERFACE_MODE_LOOP; - else - return CVMX_HELPER_INTERFACE_MODE_DISABLED; - } - - if (interface == 0 - && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5 - && cvmx_sysinfo_get()->board_rev_major == 1) { - /* - * Lie about interface type of CN3005 board. This - * board has a switch on port 1 like the other - * evaluation boards, but it is connected over RGMII - * instead of GMII. Report GMII mode so that the - * speed is forced to 1 Gbit full duplex. Other than - * some initial configuration (which does not use the - * output of this function) there is no difference in - * setup between GMII and RGMII modes. - */ - return CVMX_HELPER_INTERFACE_MODE_GMII; - } - - /* Interface 1 is always disabled on CN31XX and CN30XX */ - if ((interface == 1) - && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX) - || OCTEON_IS_MODEL(OCTEON_CN50XX) - || OCTEON_IS_MODEL(OCTEON_CN52XX))) - return CVMX_HELPER_INTERFACE_MODE_DISABLED; - - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - - if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) { - switch (mode.cn56xx.mode) { - case 0: - return CVMX_HELPER_INTERFACE_MODE_DISABLED; - case 1: - return CVMX_HELPER_INTERFACE_MODE_XAUI; - case 2: - return CVMX_HELPER_INTERFACE_MODE_SGMII; - case 3: - return CVMX_HELPER_INTERFACE_MODE_PICMG; - default: - return CVMX_HELPER_INTERFACE_MODE_DISABLED; - } - } else { - if (!mode.s.en) - return CVMX_HELPER_INTERFACE_MODE_DISABLED; - - if (mode.s.type) { - if (OCTEON_IS_MODEL(OCTEON_CN38XX) - || OCTEON_IS_MODEL(OCTEON_CN58XX)) - return CVMX_HELPER_INTERFACE_MODE_SPI; - else - return CVMX_HELPER_INTERFACE_MODE_GMII; - } else - return CVMX_HELPER_INTERFACE_MODE_RGMII; - } -} - -/** - * Configure the IPD/PIP tagging and QoS options for a specific - * port. This function determines the POW work queue entry - * contents for a port. The setup performed here is controlled by - * the defines in executive-config.h. - * - * @ipd_port: Port to configure. This follows the IPD numbering, not the - * per interface numbering - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_port_setup_ipd(int ipd_port) -{ - union cvmx_pip_prt_cfgx port_config; - union cvmx_pip_prt_tagx tag_config; - - port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port)); - tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port)); - - /* Have each port go to a different POW queue */ - port_config.s.qos = ipd_port & 0x7; - - /* Process the headers and place the IP header in the work queue */ - port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE; - - tag_config.s.ip6_src_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP; - tag_config.s.ip6_dst_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP; - tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT; - tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT; - tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER; - tag_config.s.ip4_src_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP; - tag_config.s.ip4_dst_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP; - tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT; - tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT; - tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL; - tag_config.s.inc_prt_flag = CVMX_HELPER_INPUT_TAG_INPUT_PORT; - tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - /* Put all packets in group 0. Other groups can be used by the app */ - tag_config.s.grp = 0; - - cvmx_pip_config_port(ipd_port, port_config, tag_config); - - /* Give the user a chance to override our setting for each port */ - if (cvmx_override_ipd_port_setup) - cvmx_override_ipd_port_setup(ipd_port); - - return 0; -} - -/** - * This function probes an interface to determine the actual - * number of hardware ports connected to it. It doesn't setup the - * ports or enable them. The main goal here is to set the global - * interface_port_count[interface] correctly. Hardware setup of the - * ports will be performed later. - * - * @interface: Interface to probe - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_interface_probe(int interface) -{ - /* At this stage in the game we don't want packets to be moving yet. - The following probe calls should perform hardware setup - needed to determine port counts. Receive must still be disabled */ - switch (cvmx_helper_interface_get_mode(interface)) { - /* These types don't support ports to IPD/PKO */ - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - case CVMX_HELPER_INTERFACE_MODE_PCIE: - interface_port_count[interface] = 0; - break; - /* XAUI is a single high speed port */ - case CVMX_HELPER_INTERFACE_MODE_XAUI: - interface_port_count[interface] = - __cvmx_helper_xaui_probe(interface); - break; - /* - * RGMII/GMII/MII are all treated about the same. Most - * functions refer to these ports as RGMII. - */ - case CVMX_HELPER_INTERFACE_MODE_RGMII: - case CVMX_HELPER_INTERFACE_MODE_GMII: - interface_port_count[interface] = - __cvmx_helper_rgmii_probe(interface); - break; - /* - * SPI4 can have 1-16 ports depending on the device at - * the other end. - */ - case CVMX_HELPER_INTERFACE_MODE_SPI: - interface_port_count[interface] = - __cvmx_helper_spi_probe(interface); - break; - /* - * SGMII can have 1-4 ports depending on how many are - * hooked up. - */ - case CVMX_HELPER_INTERFACE_MODE_SGMII: - case CVMX_HELPER_INTERFACE_MODE_PICMG: - interface_port_count[interface] = - __cvmx_helper_sgmii_probe(interface); - break; - /* PCI target Network Packet Interface */ - case CVMX_HELPER_INTERFACE_MODE_NPI: - interface_port_count[interface] = - __cvmx_helper_npi_probe(interface); - break; - /* - * Special loopback only ports. These are not the same - * as other ports in loopback mode. - */ - case CVMX_HELPER_INTERFACE_MODE_LOOP: - interface_port_count[interface] = - __cvmx_helper_loop_probe(interface); - break; - } - - interface_port_count[interface] = - __cvmx_helper_board_interface_probe(interface, - interface_port_count - [interface]); - - /* Make sure all global variables propagate to other cores */ - CVMX_SYNCWS; - - return 0; -} - -/** - * Setup the IPD/PIP for the ports on an interface. Packet - * classification and tagging are set for every port on the - * interface. The number of ports on the interface must already - * have been probed. - * - * @interface: Interface to setup IPD/PIP for - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_interface_setup_ipd(int interface) -{ - int ipd_port = cvmx_helper_get_ipd_port(interface, 0); - int num_ports = interface_port_count[interface]; - - while (num_ports--) { - __cvmx_helper_port_setup_ipd(ipd_port); - ipd_port++; - } - return 0; -} - -/** - * Setup global setting for IPD/PIP not related to a specific - * interface or port. This must be called before IPD is enabled. - * - * Returns Zero on success, negative on failure. - */ -static int __cvmx_helper_global_setup_ipd(void) -{ - /* Setup the global packet input options */ - cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8, - CVMX_HELPER_FIRST_MBUFF_SKIP / 8, - CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8, - /* The +8 is to account for the next ptr */ - (CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128, - /* The +8 is to account for the next ptr */ - (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128, - CVMX_FPA_WQE_POOL, - CVMX_IPD_OPC_MODE_STT, - CVMX_HELPER_ENABLE_BACK_PRESSURE); - return 0; -} - -/** - * Setup the PKO for the ports on an interface. The number of - * queues per port and the priority of each PKO output queue - * is set here. PKO must be disabled when this function is called. - * - * @interface: Interface to setup PKO for - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_interface_setup_pko(int interface) -{ - /* - * Each packet output queue has an associated priority. The - * higher the priority, the more often it can send a packet. A - * priority of 8 means it can send in all 8 rounds of - * contention. We're going to make each queue one less than - * the last. The vector of priorities has been extended to - * support CN5xxx CPUs, where up to 16 queues can be - * associated to a port. To keep backward compatibility we - * don't change the initial 8 priorities and replicate them in - * the second half. With per-core PKO queues (PKO lockless - * operation) all queues have the same priority. - */ - uint64_t priorities[16] = - { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 }; - - /* - * Setup the IPD/PIP and PKO for the ports discovered - * above. Here packet classification, tagging and output - * priorities are set. - */ - int ipd_port = cvmx_helper_get_ipd_port(interface, 0); - int num_ports = interface_port_count[interface]; - while (num_ports--) { - /* - * Give the user a chance to override the per queue - * priorities. - */ - if (cvmx_override_pko_queue_priority) - cvmx_override_pko_queue_priority(ipd_port, priorities); - - cvmx_pko_config_port(ipd_port, - cvmx_pko_get_base_queue_per_core(ipd_port, - 0), - cvmx_pko_get_num_queues(ipd_port), - priorities); - ipd_port++; - } - return 0; -} - -/** - * Setup global setting for PKO not related to a specific - * interface or port. This must be called before PKO is enabled. - * - * Returns Zero on success, negative on failure. - */ -static int __cvmx_helper_global_setup_pko(void) -{ - /* - * Disable tagwait FAU timeout. This needs to be done before - * anyone might start packet output using tags. - */ - union cvmx_iob_fau_timeout fau_to; - fau_to.u64 = 0; - fau_to.s.tout_val = 0xfff; - fau_to.s.tout_enb = 0; - cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); - return 0; -} - -/** - * Setup global backpressure setting. - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_global_setup_backpressure(void) -{ -#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE - /* Disable backpressure if configured to do so */ - /* Disable backpressure (pause frame) generation */ - int num_interfaces = cvmx_helper_get_number_of_interfaces(); - int interface; - for (interface = 0; interface < num_interfaces; interface++) { - switch (cvmx_helper_interface_get_mode(interface)) { - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - case CVMX_HELPER_INTERFACE_MODE_PCIE: - case CVMX_HELPER_INTERFACE_MODE_NPI: - case CVMX_HELPER_INTERFACE_MODE_LOOP: - case CVMX_HELPER_INTERFACE_MODE_XAUI: - break; - case CVMX_HELPER_INTERFACE_MODE_RGMII: - case CVMX_HELPER_INTERFACE_MODE_GMII: - case CVMX_HELPER_INTERFACE_MODE_SPI: - case CVMX_HELPER_INTERFACE_MODE_SGMII: - case CVMX_HELPER_INTERFACE_MODE_PICMG: - cvmx_gmx_set_backpressure_override(interface, 0xf); - break; - } - } -#endif - - return 0; -} - -/** - * Enable packet input/output from the hardware. This function is - * called after all internal setup is complete and IPD is enabled. - * After this function completes, packets will be accepted from the - * hardware ports. PKO should still be disabled to make sure packets - * aren't sent out partially setup hardware. - * - * @interface: Interface to enable - * - * Returns Zero on success, negative on failure - */ -static int __cvmx_helper_packet_hardware_enable(int interface) -{ - int result = 0; - switch (cvmx_helper_interface_get_mode(interface)) { - /* These types don't support ports to IPD/PKO */ - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - case CVMX_HELPER_INTERFACE_MODE_PCIE: - /* Nothing to do */ - break; - /* XAUI is a single high speed port */ - case CVMX_HELPER_INTERFACE_MODE_XAUI: - result = __cvmx_helper_xaui_enable(interface); - break; - /* - * RGMII/GMII/MII are all treated about the same. Most - * functions refer to these ports as RGMII - */ - case CVMX_HELPER_INTERFACE_MODE_RGMII: - case CVMX_HELPER_INTERFACE_MODE_GMII: - result = __cvmx_helper_rgmii_enable(interface); - break; - /* - * SPI4 can have 1-16 ports depending on the device at - * the other end - */ - case CVMX_HELPER_INTERFACE_MODE_SPI: - result = __cvmx_helper_spi_enable(interface); - break; - /* - * SGMII can have 1-4 ports depending on how many are - * hooked up - */ - case CVMX_HELPER_INTERFACE_MODE_SGMII: - case CVMX_HELPER_INTERFACE_MODE_PICMG: - result = __cvmx_helper_sgmii_enable(interface); - break; - /* PCI target Network Packet Interface */ - case CVMX_HELPER_INTERFACE_MODE_NPI: - result = __cvmx_helper_npi_enable(interface); - break; - /* - * Special loopback only ports. These are not the same - * as other ports in loopback mode - */ - case CVMX_HELPER_INTERFACE_MODE_LOOP: - result = __cvmx_helper_loop_enable(interface); - break; - } - result |= __cvmx_helper_board_hardware_enable(interface); - return result; -} - -/** - * Function to adjust internal IPD pointer alignments - * - * Returns 0 on success - * !0 on failure - */ -int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) -{ -#define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \ - (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP) -#define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \ - (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP) -#define FIX_IPD_OUTPORT 0 - /* Ports 0-15 are interface 0, 16-31 are interface 1 */ -#define INTERFACE(port) (port >> 4) -#define INDEX(port) (port & 0xf) - uint64_t *p64; - cvmx_pko_command_word0_t pko_command; - union cvmx_buf_ptr g_buffer, pkt_buffer; - cvmx_wqe_t *work; - int size, num_segs = 0, wqe_pcnt, pkt_pcnt; - union cvmx_gmxx_prtx_cfg gmx_cfg; - int retry_cnt; - int retry_loop_cnt; - int mtu; - int i; - cvmx_helper_link_info_t link_info; - - /* Save values for restore at end */ - uint64_t prtx_cfg = - cvmx_read_csr(CVMX_GMXX_PRTX_CFG - (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); - uint64_t tx_ptr_en = - cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); - uint64_t rx_ptr_en = - cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); - uint64_t rxx_jabber = - cvmx_read_csr(CVMX_GMXX_RXX_JABBER - (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); - uint64_t frame_max = - cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX - (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); - - /* Configure port to gig FDX as required for loopback mode */ - cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT); - - /* - * Disable reception on all ports so if traffic is present it - * will not interfere. - */ - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0); - - cvmx_wait(100000000ull); - - for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) { - retry_cnt = 100000; - wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT); - pkt_pcnt = (wqe_pcnt >> 7) & 0x7f; - wqe_pcnt &= 0x7f; - - num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3; - - if (num_segs == 0) - goto fix_ipd_exit; - - num_segs += 1; - - size = - FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES + - ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) - - (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2); - - cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), - 1 << INDEX(FIX_IPD_OUTPORT)); - CVMX_SYNC; - - g_buffer.u64 = 0; - g_buffer.s.addr = - cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL)); - if (g_buffer.s.addr == 0) { - cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " - "buffer allocation failure.\n"); - goto fix_ipd_exit; - } - - g_buffer.s.pool = CVMX_FPA_WQE_POOL; - g_buffer.s.size = num_segs; - - pkt_buffer.u64 = 0; - pkt_buffer.s.addr = - cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL)); - if (pkt_buffer.s.addr == 0) { - cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " - "buffer allocation failure.\n"); - goto fix_ipd_exit; - } - pkt_buffer.s.i = 1; - pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL; - pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES; - - p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr); - p64[0] = 0xffffffffffff0000ull; - p64[1] = 0x08004510ull; - p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull; - p64[3] = 0x3a5fc0a81073c0a8ull; - - for (i = 0; i < num_segs; i++) { - if (i > 0) - pkt_buffer.s.size = - FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES; - - if (i == (num_segs - 1)) - pkt_buffer.s.i = 0; - - *(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr + - 8 * i) = pkt_buffer.u64; - } - - /* Build the PKO command */ - pko_command.u64 = 0; - pko_command.s.segs = num_segs; - pko_command.s.total_bytes = size; - pko_command.s.dontfree = 0; - pko_command.s.gather = 1; - - gmx_cfg.u64 = - cvmx_read_csr(CVMX_GMXX_PRTX_CFG - (INDEX(FIX_IPD_OUTPORT), - INTERFACE(FIX_IPD_OUTPORT))); - gmx_cfg.s.en = 1; - cvmx_write_csr(CVMX_GMXX_PRTX_CFG - (INDEX(FIX_IPD_OUTPORT), - INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64); - cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), - 1 << INDEX(FIX_IPD_OUTPORT)); - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), - 1 << INDEX(FIX_IPD_OUTPORT)); - - mtu = - cvmx_read_csr(CVMX_GMXX_RXX_JABBER - (INDEX(FIX_IPD_OUTPORT), - INTERFACE(FIX_IPD_OUTPORT))); - cvmx_write_csr(CVMX_GMXX_RXX_JABBER - (INDEX(FIX_IPD_OUTPORT), - INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); - cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX - (INDEX(FIX_IPD_OUTPORT), - INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4); - - cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT, - cvmx_pko_get_base_queue - (FIX_IPD_OUTPORT), - CVMX_PKO_LOCK_CMD_QUEUE); - cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT, - cvmx_pko_get_base_queue - (FIX_IPD_OUTPORT), pko_command, - g_buffer, CVMX_PKO_LOCK_CMD_QUEUE); - - CVMX_SYNC; - - do { - work = cvmx_pow_work_request_sync(CVMX_POW_WAIT); - retry_cnt--; - } while ((work == NULL) && (retry_cnt > 0)); - - if (!retry_cnt) - cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " - "get_work() timeout occurred.\n"); - - /* Free packet */ - if (work) - cvmx_helper_free_packet_data(work); - } - -fix_ipd_exit: - - /* Return CSR configs to saved values */ - cvmx_write_csr(CVMX_GMXX_PRTX_CFG - (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), - prtx_cfg); - cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), - tx_ptr_en); - cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), - rx_ptr_en); - cvmx_write_csr(CVMX_GMXX_RXX_JABBER - (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), - rxx_jabber); - cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX - (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), - frame_max); - cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0); - /* Set link to down so autonegotiation will set it up again */ - link_info.u64 = 0; - cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info); - - /* - * Bring the link back up as autonegotiation is not done in - * user applications. - */ - cvmx_helper_link_autoconf(FIX_IPD_OUTPORT); - - CVMX_SYNC; - if (num_segs) - cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n"); - - return !!num_segs; - -} - -/** - * Called after all internal packet IO paths are setup. This - * function enables IPD/PIP and begins packet input and output. - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_ipd_and_packet_input_enable(void) -{ - int num_interfaces; - int interface; - - /* Enable IPD */ - cvmx_ipd_enable(); - - /* - * Time to enable hardware ports packet input and output. Note - * that at this point IPD/PIP must be fully functional and PKO - * must be disabled - */ - num_interfaces = cvmx_helper_get_number_of_interfaces(); - for (interface = 0; interface < num_interfaces; interface++) { - if (cvmx_helper_ports_on_interface(interface) > 0) - __cvmx_helper_packet_hardware_enable(interface); - } - - /* Finally enable PKO now that the entire path is up and running */ - cvmx_pko_enable(); - - if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1) - || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1)) - && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)) - __cvmx_helper_errata_fix_ipd_ptr_alignment(); - return 0; -} - -/** - * Initialize the PIP, IPD, and PKO hardware to support - * simple priority based queues for the ethernet ports. Each - * port is configured with a number of priority queues based - * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower - * priority than the previous. - * - * Returns Zero on success, non-zero on failure - */ -int cvmx_helper_initialize_packet_io_global(void) -{ - int result = 0; - int interface; - union cvmx_l2c_cfg l2c_cfg; - union cvmx_smix_en smix_en; - const int num_interfaces = cvmx_helper_get_number_of_interfaces(); - - /* - * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to - * be disabled. - */ - if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0)) - __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1); - - /* - * Tell L2 to give the IOB statically higher priority compared - * to the cores. This avoids conditions where IO blocks might - * be starved under very high L2 loads. - */ - l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); - l2c_cfg.s.lrf_arb_mode = 0; - l2c_cfg.s.rfb_arb_mode = 0; - cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64); - - /* Make sure SMI/MDIO is enabled so we can query PHYs */ - smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0)); - if (!smix_en.s.en) { - smix_en.s.en = 1; - cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64); - } - - /* Newer chips actually have two SMI/MDIO interfaces */ - if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) && - !OCTEON_IS_MODEL(OCTEON_CN58XX) && - !OCTEON_IS_MODEL(OCTEON_CN50XX)) { - smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1)); - if (!smix_en.s.en) { - smix_en.s.en = 1; - cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64); - } - } - - cvmx_pko_initialize_global(); - for (interface = 0; interface < num_interfaces; interface++) { - result |= cvmx_helper_interface_probe(interface); - if (cvmx_helper_ports_on_interface(interface) > 0) - cvmx_dprintf("Interface %d has %d ports (%s)\n", - interface, - cvmx_helper_ports_on_interface(interface), - cvmx_helper_interface_mode_to_string - (cvmx_helper_interface_get_mode - (interface))); - result |= __cvmx_helper_interface_setup_ipd(interface); - result |= __cvmx_helper_interface_setup_pko(interface); - } - - result |= __cvmx_helper_global_setup_ipd(); - result |= __cvmx_helper_global_setup_pko(); - - /* Enable any flow control and backpressure */ - result |= __cvmx_helper_global_setup_backpressure(); - -#if CVMX_HELPER_ENABLE_IPD - result |= cvmx_helper_ipd_and_packet_input_enable(); -#endif - return result; -} - -/** - * Does core local initialization for packet io - * - * Returns Zero on success, non-zero on failure - */ -int cvmx_helper_initialize_packet_io_local(void) -{ - return cvmx_pko_initialize_local(); -} - -/** - * Auto configure an IPD/PKO port link state and speed. This - * function basically does the equivalent of: - * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); - * - * @ipd_port: IPD/PKO port to auto configure - * - * Returns Link state after configure - */ -cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port) -{ - cvmx_helper_link_info_t link_info; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - - if (index >= cvmx_helper_ports_on_interface(interface)) { - link_info.u64 = 0; - return link_info; - } - - link_info = cvmx_helper_link_get(ipd_port); - if (link_info.u64 == port_link_info[ipd_port].u64) - return link_info; - - /* If we fail to set the link speed, port_link_info will not change */ - cvmx_helper_link_set(ipd_port, link_info); - - /* - * port_link_info should be the current value, which will be - * different than expect if cvmx_helper_link_set() failed. - */ - return port_link_info[ipd_port]; -} - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port) -{ - cvmx_helper_link_info_t result; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - - /* The default result will be a down link unless the code below - changes it */ - result.u64 = 0; - - if (index >= cvmx_helper_ports_on_interface(interface)) - return result; - - switch (cvmx_helper_interface_get_mode(interface)) { - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - case CVMX_HELPER_INTERFACE_MODE_PCIE: - /* Network links are not supported */ - break; - case CVMX_HELPER_INTERFACE_MODE_XAUI: - result = __cvmx_helper_xaui_link_get(ipd_port); - break; - case CVMX_HELPER_INTERFACE_MODE_GMII: - if (index == 0) - result = __cvmx_helper_rgmii_link_get(ipd_port); - else { - result.s.full_duplex = 1; - result.s.link_up = 1; - result.s.speed = 1000; - } - break; - case CVMX_HELPER_INTERFACE_MODE_RGMII: - result = __cvmx_helper_rgmii_link_get(ipd_port); - break; - case CVMX_HELPER_INTERFACE_MODE_SPI: - result = __cvmx_helper_spi_link_get(ipd_port); - break; - case CVMX_HELPER_INTERFACE_MODE_SGMII: - case CVMX_HELPER_INTERFACE_MODE_PICMG: - result = __cvmx_helper_sgmii_link_get(ipd_port); - break; - case CVMX_HELPER_INTERFACE_MODE_NPI: - case CVMX_HELPER_INTERFACE_MODE_LOOP: - /* Network links are not supported */ - break; - } - return result; -} - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info) -{ - int result = -1; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - - if (index >= cvmx_helper_ports_on_interface(interface)) - return -1; - - switch (cvmx_helper_interface_get_mode(interface)) { - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - case CVMX_HELPER_INTERFACE_MODE_PCIE: - break; - case CVMX_HELPER_INTERFACE_MODE_XAUI: - result = __cvmx_helper_xaui_link_set(ipd_port, link_info); - break; - /* - * RGMII/GMII/MII are all treated about the same. Most - * functions refer to these ports as RGMII. - */ - case CVMX_HELPER_INTERFACE_MODE_RGMII: - case CVMX_HELPER_INTERFACE_MODE_GMII: - result = __cvmx_helper_rgmii_link_set(ipd_port, link_info); - break; - case CVMX_HELPER_INTERFACE_MODE_SPI: - result = __cvmx_helper_spi_link_set(ipd_port, link_info); - break; - case CVMX_HELPER_INTERFACE_MODE_SGMII: - case CVMX_HELPER_INTERFACE_MODE_PICMG: - result = __cvmx_helper_sgmii_link_set(ipd_port, link_info); - break; - case CVMX_HELPER_INTERFACE_MODE_NPI: - case CVMX_HELPER_INTERFACE_MODE_LOOP: - break; - } - /* Set the port_link_info here so that the link status is updated - no matter how cvmx_helper_link_set is called. We don't change - the value if link_set failed */ - if (result == 0) - port_link_info[ipd_port].u64 = link_info.u64; - return result; -} - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, - int enable_external) -{ - int result = -1; - int interface = cvmx_helper_get_interface_num(ipd_port); - int index = cvmx_helper_get_interface_index_num(ipd_port); - - if (index >= cvmx_helper_ports_on_interface(interface)) - return -1; - - switch (cvmx_helper_interface_get_mode(interface)) { - case CVMX_HELPER_INTERFACE_MODE_DISABLED: - case CVMX_HELPER_INTERFACE_MODE_PCIE: - case CVMX_HELPER_INTERFACE_MODE_SPI: - case CVMX_HELPER_INTERFACE_MODE_NPI: - case CVMX_HELPER_INTERFACE_MODE_LOOP: - break; - case CVMX_HELPER_INTERFACE_MODE_XAUI: - result = - __cvmx_helper_xaui_configure_loopback(ipd_port, - enable_internal, - enable_external); - break; - case CVMX_HELPER_INTERFACE_MODE_RGMII: - case CVMX_HELPER_INTERFACE_MODE_GMII: - result = - __cvmx_helper_rgmii_configure_loopback(ipd_port, - enable_internal, - enable_external); - break; - case CVMX_HELPER_INTERFACE_MODE_SGMII: - case CVMX_HELPER_INTERFACE_MODE_PICMG: - result = - __cvmx_helper_sgmii_configure_loopback(ipd_port, - enable_internal, - enable_external); - break; - } - return result; -} diff --git a/drivers/staging/octeon/cvmx-helper.h b/drivers/staging/octeon/cvmx-helper.h deleted file mode 100644 index 51916f3cc40c..000000000000 --- a/drivers/staging/octeon/cvmx-helper.h +++ /dev/null @@ -1,227 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Helper functions for common, but complicated tasks. - * - */ - -#ifndef __CVMX_HELPER_H__ -#define __CVMX_HELPER_H__ - -#include "cvmx-config.h" -#include "cvmx-fpa.h" -#include "cvmx-wqe.h" - -typedef enum { - CVMX_HELPER_INTERFACE_MODE_DISABLED, - CVMX_HELPER_INTERFACE_MODE_RGMII, - CVMX_HELPER_INTERFACE_MODE_GMII, - CVMX_HELPER_INTERFACE_MODE_SPI, - CVMX_HELPER_INTERFACE_MODE_PCIE, - CVMX_HELPER_INTERFACE_MODE_XAUI, - CVMX_HELPER_INTERFACE_MODE_SGMII, - CVMX_HELPER_INTERFACE_MODE_PICMG, - CVMX_HELPER_INTERFACE_MODE_NPI, - CVMX_HELPER_INTERFACE_MODE_LOOP, -} cvmx_helper_interface_mode_t; - -typedef union { - uint64_t u64; - struct { - uint64_t reserved_20_63:44; - uint64_t link_up:1; /**< Is the physical link up? */ - uint64_t full_duplex:1; /**< 1 if the link is full duplex */ - uint64_t speed:18; /**< Speed of the link in Mbps */ - } s; -} cvmx_helper_link_info_t; - -#include "cvmx-helper-fpa.h" - -#include <asm/octeon/cvmx-helper-errata.h> -#include "cvmx-helper-loop.h" -#include "cvmx-helper-npi.h" -#include "cvmx-helper-rgmii.h" -#include "cvmx-helper-sgmii.h" -#include "cvmx-helper-spi.h" -#include "cvmx-helper-util.h" -#include "cvmx-helper-xaui.h" - -/** - * cvmx_override_pko_queue_priority(int ipd_port, uint64_t - * priorities[16]) is a function pointer. It is meant to allow - * customization of the PKO queue priorities based on the port - * number. Users should set this pointer to a function before - * calling any cvmx-helper operations. - */ -extern void (*cvmx_override_pko_queue_priority) (int pko_port, - uint64_t priorities[16]); - -/** - * cvmx_override_ipd_port_setup(int ipd_port) is a function - * pointer. It is meant to allow customization of the IPD port - * setup before packet input/output comes online. It is called - * after cvmx-helper does the default IPD configuration, but - * before IPD is enabled. Users should set this pointer to a - * function before calling any cvmx-helper operations. - */ -extern void (*cvmx_override_ipd_port_setup) (int ipd_port); - -/** - * This function enables the IPD and also enables the packet interfaces. - * The packet interfaces (RGMII and SPI) must be enabled after the - * IPD. This should be called by the user program after any additional - * IPD configuration changes are made if CVMX_HELPER_ENABLE_IPD - * is not set in the executive-config.h file. - * - * Returns 0 on success - * -1 on failure - */ -extern int cvmx_helper_ipd_and_packet_input_enable(void); - -/** - * Initialize the PIP, IPD, and PKO hardware to support - * simple priority based queues for the ethernet ports. Each - * port is configured with a number of priority queues based - * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower - * priority than the previous. - * - * Returns Zero on success, non-zero on failure - */ -extern int cvmx_helper_initialize_packet_io_global(void); - -/** - * Does core local initialization for packet io - * - * Returns Zero on success, non-zero on failure - */ -extern int cvmx_helper_initialize_packet_io_local(void); - -/** - * Returns the number of ports on the given interface. - * The interface must be initialized before the port count - * can be returned. - * - * @interface: Which interface to return port count for. - * - * Returns Port count for interface - * -1 for uninitialized interface - */ -extern int cvmx_helper_ports_on_interface(int interface); - -/** - * Return the number of interfaces the chip has. Each interface - * may have multiple ports. Most chips support two interfaces, - * but the CNX0XX and CNX1XX are exceptions. These only support - * one interface. - * - * Returns Number of interfaces on chip - */ -extern int cvmx_helper_get_number_of_interfaces(void); - -/** - * Get the operating mode of an interface. Depending on the Octeon - * chip and configuration, this function returns an enumeration - * of the type of packet I/O supported by an interface. - * - * @interface: Interface to probe - * - * Returns Mode of the interface. Unknown or unsupported interfaces return - * DISABLED. - */ -extern cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int - interface); - -/** - * Auto configure an IPD/PKO port link state and speed. This - * function basically does the equivalent of: - * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port)); - * - * @ipd_port: IPD/PKO port to auto configure - * - * Returns Link state after configure - */ -extern cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port); - -/** - * Return the link state of an IPD/PKO port as returned by - * auto negotiation. The result of this function may not match - * Octeon's link config if auto negotiation has changed since - * the last call to cvmx_helper_link_set(). - * - * @ipd_port: IPD/PKO port to query - * - * Returns Link state - */ -extern cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port); - -/** - * Configure an IPD/PKO port for the specified link state. This - * function does not influence auto negotiation at the PHY level. - * The passed link state must always match the link state returned - * by cvmx_helper_link_get(). It is normally best to use - * cvmx_helper_link_autoconf() instead. - * - * @ipd_port: IPD/PKO port to configure - * @link_info: The new link state - * - * Returns Zero on success, negative on failure - */ -extern int cvmx_helper_link_set(int ipd_port, - cvmx_helper_link_info_t link_info); - -/** - * This function probes an interface to determine the actual - * number of hardware ports connected to it. It doesn't setup the - * ports or enable them. The main goal here is to set the global - * interface_port_count[interface] correctly. Hardware setup of the - * ports will be performed later. - * - * @interface: Interface to probe - * - * Returns Zero on success, negative on failure - */ -extern int cvmx_helper_interface_probe(int interface); - -/** - * Configure a port for internal and/or external loopback. Internal loopback - * causes packets sent by the port to be received by Octeon. External loopback - * causes packets received from the wire to sent out again. - * - * @ipd_port: IPD/PKO port to loopback. - * @enable_internal: - * Non zero if you want internal loopback - * @enable_external: - * Non zero if you want external loopback - * - * Returns Zero on success, negative on failure. - */ -extern int cvmx_helper_configure_loopback(int ipd_port, int enable_internal, - int enable_external); - -#endif /* __CVMX_HELPER_H__ */ diff --git a/drivers/staging/octeon/cvmx-interrupt-decodes.c b/drivers/staging/octeon/cvmx-interrupt-decodes.c deleted file mode 100644 index a3337e382ee9..000000000000 --- a/drivers/staging/octeon/cvmx-interrupt-decodes.c +++ /dev/null @@ -1,371 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2009 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Automatically generated functions useful for enabling - * and decoding RSL_INT_BLOCKS interrupts. - * - */ - -#include <asm/octeon/octeon.h> - -#include "cvmx-gmxx-defs.h" -#include "cvmx-pcsx-defs.h" -#include "cvmx-pcsxx-defs.h" -#include "cvmx-spxx-defs.h" -#include "cvmx-stxx-defs.h" - -#ifndef PRINT_ERROR -#define PRINT_ERROR(format, ...) -#endif - - -/** - * __cvmx_interrupt_gmxx_rxx_int_en_enable enables all interrupt bits in cvmx_gmxx_rxx_int_en_t - */ -void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block) -{ - union cvmx_gmxx_rxx_int_en gmx_rx_int_en; - cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, block), - cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, block))); - gmx_rx_int_en.u64 = 0; - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { - /* Skipping gmx_rx_int_en.s.reserved_29_63 */ - gmx_rx_int_en.s.hg2cc = 1; - gmx_rx_int_en.s.hg2fld = 1; - gmx_rx_int_en.s.undat = 1; - gmx_rx_int_en.s.uneop = 1; - gmx_rx_int_en.s.unsop = 1; - gmx_rx_int_en.s.bad_term = 1; - gmx_rx_int_en.s.bad_seq = 1; - gmx_rx_int_en.s.rem_fault = 1; - gmx_rx_int_en.s.loc_fault = 1; - gmx_rx_int_en.s.pause_drp = 1; - /* Skipping gmx_rx_int_en.s.reserved_16_18 */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - /* Skipping gmx_rx_int_en.s.reserved_9_9 */ - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /* Skipping gmx_rx_int_en.s.reserved_5_6 */ - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - /* Skipping gmx_rx_int_en.s.reserved_2_2 */ - gmx_rx_int_en.s.carext = 1; - /* Skipping gmx_rx_int_en.s.reserved_0_0 */ - } - if (OCTEON_IS_MODEL(OCTEON_CN30XX)) { - /* Skipping gmx_rx_int_en.s.reserved_19_63 */ - /*gmx_rx_int_en.s.phy_dupx = 1; */ - /*gmx_rx_int_en.s.phy_spd = 1; */ - /*gmx_rx_int_en.s.phy_link = 1; */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - gmx_rx_int_en.s.niberr = 1; - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ - gmx_rx_int_en.s.alnerr = 1; - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - gmx_rx_int_en.s.maxerr = 1; - gmx_rx_int_en.s.carext = 1; - gmx_rx_int_en.s.minerr = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { - /* Skipping gmx_rx_int_en.s.reserved_20_63 */ - gmx_rx_int_en.s.pause_drp = 1; - /*gmx_rx_int_en.s.phy_dupx = 1; */ - /*gmx_rx_int_en.s.phy_spd = 1; */ - /*gmx_rx_int_en.s.phy_link = 1; */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - gmx_rx_int_en.s.niberr = 1; - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /* Skipping gmx_rx_int_en.s.reserved_6_6 */ - gmx_rx_int_en.s.alnerr = 1; - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - /* Skipping gmx_rx_int_en.s.reserved_2_2 */ - gmx_rx_int_en.s.carext = 1; - /* Skipping gmx_rx_int_en.s.reserved_0_0 */ - } - if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { - /* Skipping gmx_rx_int_en.s.reserved_19_63 */ - /*gmx_rx_int_en.s.phy_dupx = 1; */ - /*gmx_rx_int_en.s.phy_spd = 1; */ - /*gmx_rx_int_en.s.phy_link = 1; */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - gmx_rx_int_en.s.niberr = 1; - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ - gmx_rx_int_en.s.alnerr = 1; - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - gmx_rx_int_en.s.maxerr = 1; - gmx_rx_int_en.s.carext = 1; - gmx_rx_int_en.s.minerr = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN31XX)) { - /* Skipping gmx_rx_int_en.s.reserved_19_63 */ - /*gmx_rx_int_en.s.phy_dupx = 1; */ - /*gmx_rx_int_en.s.phy_spd = 1; */ - /*gmx_rx_int_en.s.phy_link = 1; */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - gmx_rx_int_en.s.niberr = 1; - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ - gmx_rx_int_en.s.alnerr = 1; - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - gmx_rx_int_en.s.maxerr = 1; - gmx_rx_int_en.s.carext = 1; - gmx_rx_int_en.s.minerr = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN58XX)) { - /* Skipping gmx_rx_int_en.s.reserved_20_63 */ - gmx_rx_int_en.s.pause_drp = 1; - /*gmx_rx_int_en.s.phy_dupx = 1; */ - /*gmx_rx_int_en.s.phy_spd = 1; */ - /*gmx_rx_int_en.s.phy_link = 1; */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - gmx_rx_int_en.s.niberr = 1; - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */ - gmx_rx_int_en.s.alnerr = 1; - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - gmx_rx_int_en.s.maxerr = 1; - gmx_rx_int_en.s.carext = 1; - gmx_rx_int_en.s.minerr = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { - /* Skipping gmx_rx_int_en.s.reserved_29_63 */ - gmx_rx_int_en.s.hg2cc = 1; - gmx_rx_int_en.s.hg2fld = 1; - gmx_rx_int_en.s.undat = 1; - gmx_rx_int_en.s.uneop = 1; - gmx_rx_int_en.s.unsop = 1; - gmx_rx_int_en.s.bad_term = 1; - gmx_rx_int_en.s.bad_seq = 0; - gmx_rx_int_en.s.rem_fault = 1; - gmx_rx_int_en.s.loc_fault = 0; - gmx_rx_int_en.s.pause_drp = 1; - /* Skipping gmx_rx_int_en.s.reserved_16_18 */ - /*gmx_rx_int_en.s.ifgerr = 1; */ - /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */ - /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */ - /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */ - /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */ - gmx_rx_int_en.s.ovrerr = 1; - /* Skipping gmx_rx_int_en.s.reserved_9_9 */ - gmx_rx_int_en.s.skperr = 1; - gmx_rx_int_en.s.rcverr = 1; - /* Skipping gmx_rx_int_en.s.reserved_5_6 */ - /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */ - gmx_rx_int_en.s.jabber = 1; - /* Skipping gmx_rx_int_en.s.reserved_2_2 */ - gmx_rx_int_en.s.carext = 1; - /* Skipping gmx_rx_int_en.s.reserved_0_0 */ - } - cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, block), gmx_rx_int_en.u64); -} -/** - * __cvmx_interrupt_pcsx_intx_en_reg_enable enables all interrupt bits in cvmx_pcsx_intx_en_reg_t - */ -void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block) -{ - union cvmx_pcsx_intx_en_reg pcs_int_en_reg; - cvmx_write_csr(CVMX_PCSX_INTX_REG(index, block), - cvmx_read_csr(CVMX_PCSX_INTX_REG(index, block))); - pcs_int_en_reg.u64 = 0; - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { - /* Skipping pcs_int_en_reg.s.reserved_12_63 */ - /*pcs_int_en_reg.s.dup = 1; // This happens during normal operation */ - pcs_int_en_reg.s.sync_bad_en = 1; - pcs_int_en_reg.s.an_bad_en = 1; - pcs_int_en_reg.s.rxlock_en = 1; - pcs_int_en_reg.s.rxbad_en = 1; - /*pcs_int_en_reg.s.rxerr_en = 1; // This happens during normal operation */ - pcs_int_en_reg.s.txbad_en = 1; - pcs_int_en_reg.s.txfifo_en = 1; - pcs_int_en_reg.s.txfifu_en = 1; - pcs_int_en_reg.s.an_err_en = 1; - /*pcs_int_en_reg.s.xmit_en = 1; // This happens during normal operation */ - /*pcs_int_en_reg.s.lnkspd_en = 1; // This happens during normal operation */ - } - if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { - /* Skipping pcs_int_en_reg.s.reserved_12_63 */ - /*pcs_int_en_reg.s.dup = 1; // This happens during normal operation */ - pcs_int_en_reg.s.sync_bad_en = 1; - pcs_int_en_reg.s.an_bad_en = 1; - pcs_int_en_reg.s.rxlock_en = 1; - pcs_int_en_reg.s.rxbad_en = 1; - /*pcs_int_en_reg.s.rxerr_en = 1; // This happens during normal operation */ - pcs_int_en_reg.s.txbad_en = 1; - pcs_int_en_reg.s.txfifo_en = 1; - pcs_int_en_reg.s.txfifu_en = 1; - pcs_int_en_reg.s.an_err_en = 1; - /*pcs_int_en_reg.s.xmit_en = 1; // This happens during normal operation */ - /*pcs_int_en_reg.s.lnkspd_en = 1; // This happens during normal operation */ - } - cvmx_write_csr(CVMX_PCSX_INTX_EN_REG(index, block), pcs_int_en_reg.u64); -} -/** - * __cvmx_interrupt_pcsxx_int_en_reg_enable enables all interrupt bits in cvmx_pcsxx_int_en_reg_t - */ -void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index) -{ - union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; - cvmx_write_csr(CVMX_PCSXX_INT_REG(index), - cvmx_read_csr(CVMX_PCSXX_INT_REG(index))); - pcsx_int_en_reg.u64 = 0; - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) { - /* Skipping pcsx_int_en_reg.s.reserved_6_63 */ - pcsx_int_en_reg.s.algnlos_en = 1; - pcsx_int_en_reg.s.synlos_en = 1; - pcsx_int_en_reg.s.bitlckls_en = 1; - pcsx_int_en_reg.s.rxsynbad_en = 1; - pcsx_int_en_reg.s.rxbad_en = 1; - pcsx_int_en_reg.s.txflt_en = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN52XX)) { - /* Skipping pcsx_int_en_reg.s.reserved_6_63 */ - pcsx_int_en_reg.s.algnlos_en = 1; - pcsx_int_en_reg.s.synlos_en = 1; - pcsx_int_en_reg.s.bitlckls_en = 0; /* Happens if XAUI module is not installed */ - pcsx_int_en_reg.s.rxsynbad_en = 1; - pcsx_int_en_reg.s.rxbad_en = 1; - pcsx_int_en_reg.s.txflt_en = 1; - } - cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(index), pcsx_int_en_reg.u64); -} - -/** - * __cvmx_interrupt_spxx_int_msk_enable enables all interrupt bits in cvmx_spxx_int_msk_t - */ -void __cvmx_interrupt_spxx_int_msk_enable(int index) -{ - union cvmx_spxx_int_msk spx_int_msk; - cvmx_write_csr(CVMX_SPXX_INT_REG(index), - cvmx_read_csr(CVMX_SPXX_INT_REG(index))); - spx_int_msk.u64 = 0; - if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { - /* Skipping spx_int_msk.s.reserved_12_63 */ - spx_int_msk.s.calerr = 1; - spx_int_msk.s.syncerr = 1; - spx_int_msk.s.diperr = 1; - spx_int_msk.s.tpaovr = 1; - spx_int_msk.s.rsverr = 1; - spx_int_msk.s.drwnng = 1; - spx_int_msk.s.clserr = 1; - spx_int_msk.s.spiovr = 1; - /* Skipping spx_int_msk.s.reserved_2_3 */ - spx_int_msk.s.abnorm = 1; - spx_int_msk.s.prtnxa = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN58XX)) { - /* Skipping spx_int_msk.s.reserved_12_63 */ - spx_int_msk.s.calerr = 1; - spx_int_msk.s.syncerr = 1; - spx_int_msk.s.diperr = 1; - spx_int_msk.s.tpaovr = 1; - spx_int_msk.s.rsverr = 1; - spx_int_msk.s.drwnng = 1; - spx_int_msk.s.clserr = 1; - spx_int_msk.s.spiovr = 1; - /* Skipping spx_int_msk.s.reserved_2_3 */ - spx_int_msk.s.abnorm = 1; - spx_int_msk.s.prtnxa = 1; - } - cvmx_write_csr(CVMX_SPXX_INT_MSK(index), spx_int_msk.u64); -} -/** - * __cvmx_interrupt_stxx_int_msk_enable enables all interrupt bits in cvmx_stxx_int_msk_t - */ -void __cvmx_interrupt_stxx_int_msk_enable(int index) -{ - union cvmx_stxx_int_msk stx_int_msk; - cvmx_write_csr(CVMX_STXX_INT_REG(index), - cvmx_read_csr(CVMX_STXX_INT_REG(index))); - stx_int_msk.u64 = 0; - if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { - /* Skipping stx_int_msk.s.reserved_8_63 */ - stx_int_msk.s.frmerr = 1; - stx_int_msk.s.unxfrm = 1; - stx_int_msk.s.nosync = 1; - stx_int_msk.s.diperr = 1; - stx_int_msk.s.datovr = 1; - stx_int_msk.s.ovrbst = 1; - stx_int_msk.s.calpar1 = 1; - stx_int_msk.s.calpar0 = 1; - } - if (OCTEON_IS_MODEL(OCTEON_CN58XX)) { - /* Skipping stx_int_msk.s.reserved_8_63 */ - stx_int_msk.s.frmerr = 1; - stx_int_msk.s.unxfrm = 1; - stx_int_msk.s.nosync = 1; - stx_int_msk.s.diperr = 1; - stx_int_msk.s.datovr = 1; - stx_int_msk.s.ovrbst = 1; - stx_int_msk.s.calpar1 = 1; - stx_int_msk.s.calpar0 = 1; - } - cvmx_write_csr(CVMX_STXX_INT_MSK(index), stx_int_msk.u64); -} diff --git a/drivers/staging/octeon/cvmx-interrupt-rsl.c b/drivers/staging/octeon/cvmx-interrupt-rsl.c deleted file mode 100644 index df50048cfbc0..000000000000 --- a/drivers/staging/octeon/cvmx-interrupt-rsl.c +++ /dev/null @@ -1,140 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Utility functions to decode Octeon's RSL_INT_BLOCKS - * interrupts into error messages. - */ - -#include <asm/octeon/octeon.h> - -#include "cvmx-asxx-defs.h" -#include "cvmx-gmxx-defs.h" - -#ifndef PRINT_ERROR -#define PRINT_ERROR(format, ...) -#endif - -void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block); - -/** - * Enable ASX error interrupts that exist on CN3XXX, CN50XX, and - * CN58XX. - * - * @block: Interface to enable 0-1 - */ -void __cvmx_interrupt_asxx_enable(int block) -{ - int mask; - union cvmx_asxx_int_en csr; - /* - * CN38XX and CN58XX have two interfaces with 4 ports per - * interface. All other chips have a max of 3 ports on - * interface 0 - */ - if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) - mask = 0xf; /* Set enables for 4 ports */ - else - mask = 0x7; /* Set enables for 3 ports */ - - /* Enable interface interrupts */ - csr.u64 = cvmx_read_csr(CVMX_ASXX_INT_EN(block)); - csr.s.txpsh = mask; - csr.s.txpop = mask; - csr.s.ovrflw = mask; - cvmx_write_csr(CVMX_ASXX_INT_EN(block), csr.u64); -} -/** - * Enable GMX error reporting for the supplied interface - * - * @interface: Interface to enable - */ -void __cvmx_interrupt_gmxx_enable(int interface) -{ - union cvmx_gmxx_inf_mode mode; - union cvmx_gmxx_tx_int_en gmx_tx_int_en; - int num_ports; - int index; - - mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - - if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) { - if (mode.s.en) { - switch (mode.cn56xx.mode) { - case 1: /* XAUI */ - num_ports = 1; - break; - case 2: /* SGMII */ - case 3: /* PICMG */ - num_ports = 4; - break; - default: /* Disabled */ - num_ports = 0; - break; - } - } else - num_ports = 0; - } else { - if (mode.s.en) { - if (OCTEON_IS_MODEL(OCTEON_CN38XX) - || OCTEON_IS_MODEL(OCTEON_CN58XX)) { - /* - * SPI on CN38XX and CN58XX report all - * errors through port 0. RGMII needs - * to check all 4 ports - */ - if (mode.s.type) - num_ports = 1; - else - num_ports = 4; - } else { - /* - * CN30XX, CN31XX, and CN50XX have two - * or three ports. GMII and MII has 2, - * RGMII has three - */ - if (mode.s.type) - num_ports = 2; - else - num_ports = 3; - } - } else - num_ports = 0; - } - - gmx_tx_int_en.u64 = 0; - if (num_ports) { - if (OCTEON_IS_MODEL(OCTEON_CN38XX) - || OCTEON_IS_MODEL(OCTEON_CN58XX)) - gmx_tx_int_en.s.ncb_nxa = 1; - gmx_tx_int_en.s.pko_nxa = 1; - } - gmx_tx_int_en.s.undflw = (1 << num_ports) - 1; - cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64); - for (index = 0; index < num_ports; index++) - __cvmx_interrupt_gmxx_rxx_int_en_enable(index, interface); -} diff --git a/drivers/staging/octeon/cvmx-ipd.h b/drivers/staging/octeon/cvmx-ipd.h deleted file mode 100644 index 115a552c5c7f..000000000000 --- a/drivers/staging/octeon/cvmx-ipd.h +++ /dev/null @@ -1,338 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * Interface to the hardware Input Packet Data unit. - */ - -#ifndef __CVMX_IPD_H__ -#define __CVMX_IPD_H__ - -#include <asm/octeon/octeon-feature.h> - -#include <asm/octeon/cvmx-ipd-defs.h> - -enum cvmx_ipd_mode { - CVMX_IPD_OPC_MODE_STT = 0LL, /* All blocks DRAM, not cached in L2 */ - CVMX_IPD_OPC_MODE_STF = 1LL, /* All bloccks into L2 */ - CVMX_IPD_OPC_MODE_STF1_STT = 2LL, /* 1st block L2, rest DRAM */ - CVMX_IPD_OPC_MODE_STF2_STT = 3LL /* 1st, 2nd blocks L2, rest DRAM */ -}; - -#ifndef CVMX_ENABLE_LEN_M8_FIX -#define CVMX_ENABLE_LEN_M8_FIX 0 -#endif - -/* CSR typedefs have been moved to cvmx-csr-*.h */ -typedef union cvmx_ipd_1st_mbuff_skip cvmx_ipd_mbuff_first_skip_t; -typedef union cvmx_ipd_1st_next_ptr_back cvmx_ipd_first_next_ptr_back_t; - -typedef cvmx_ipd_mbuff_first_skip_t cvmx_ipd_mbuff_not_first_skip_t; -typedef cvmx_ipd_first_next_ptr_back_t cvmx_ipd_second_next_ptr_back_t; - -/** - * Configure IPD - * - * @mbuff_size: Packets buffer size in 8 byte words - * @first_mbuff_skip: - * Number of 8 byte words to skip in the first buffer - * @not_first_mbuff_skip: - * Number of 8 byte words to skip in each following buffer - * @first_back: Must be same as first_mbuff_skip / 128 - * @second_back: - * Must be same as not_first_mbuff_skip / 128 - * @wqe_fpa_pool: - * FPA pool to get work entries from - * @cache_mode: - * @back_pres_enable_flag: - * Enable or disable port back pressure - */ -static inline void cvmx_ipd_config(uint64_t mbuff_size, - uint64_t first_mbuff_skip, - uint64_t not_first_mbuff_skip, - uint64_t first_back, - uint64_t second_back, - uint64_t wqe_fpa_pool, - enum cvmx_ipd_mode cache_mode, - uint64_t back_pres_enable_flag) -{ - cvmx_ipd_mbuff_first_skip_t first_skip; - cvmx_ipd_mbuff_not_first_skip_t not_first_skip; - union cvmx_ipd_packet_mbuff_size size; - cvmx_ipd_first_next_ptr_back_t first_back_struct; - cvmx_ipd_second_next_ptr_back_t second_back_struct; - union cvmx_ipd_wqe_fpa_queue wqe_pool; - union cvmx_ipd_ctl_status ipd_ctl_reg; - - first_skip.u64 = 0; - first_skip.s.skip_sz = first_mbuff_skip; - cvmx_write_csr(CVMX_IPD_1ST_MBUFF_SKIP, first_skip.u64); - - not_first_skip.u64 = 0; - not_first_skip.s.skip_sz = not_first_mbuff_skip; - cvmx_write_csr(CVMX_IPD_NOT_1ST_MBUFF_SKIP, not_first_skip.u64); - - size.u64 = 0; - size.s.mb_size = mbuff_size; - cvmx_write_csr(CVMX_IPD_PACKET_MBUFF_SIZE, size.u64); - - first_back_struct.u64 = 0; - first_back_struct.s.back = first_back; - cvmx_write_csr(CVMX_IPD_1st_NEXT_PTR_BACK, first_back_struct.u64); - - second_back_struct.u64 = 0; - second_back_struct.s.back = second_back; - cvmx_write_csr(CVMX_IPD_2nd_NEXT_PTR_BACK, second_back_struct.u64); - - wqe_pool.u64 = 0; - wqe_pool.s.wqe_pool = wqe_fpa_pool; - cvmx_write_csr(CVMX_IPD_WQE_FPA_QUEUE, wqe_pool.u64); - - ipd_ctl_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); - ipd_ctl_reg.s.opc_mode = cache_mode; - ipd_ctl_reg.s.pbp_en = back_pres_enable_flag; - cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_reg.u64); - - /* Note: the example RED code that used to be here has been moved to - cvmx_helper_setup_red */ -} - -/** - * Enable IPD - */ -static inline void cvmx_ipd_enable(void) -{ - union cvmx_ipd_ctl_status ipd_reg; - ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); - if (ipd_reg.s.ipd_en) { - cvmx_dprintf - ("Warning: Enabling IPD when IPD already enabled.\n"); - } - ipd_reg.s.ipd_en = 1; -#if CVMX_ENABLE_LEN_M8_FIX - if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) - ipd_reg.s.len_m8 = TRUE; -#endif - cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64); -} - -/** - * Disable IPD - */ -static inline void cvmx_ipd_disable(void) -{ - union cvmx_ipd_ctl_status ipd_reg; - ipd_reg.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); - ipd_reg.s.ipd_en = 0; - cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_reg.u64); -} - -/** - * Supportive function for cvmx_fpa_shutdown_pool. - */ -static inline void cvmx_ipd_free_ptr(void) -{ - /* Only CN38XXp{1,2} cannot read pointer out of the IPD */ - if (!OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1) - && !OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) { - int no_wptr = 0; - union cvmx_ipd_ptr_count ipd_ptr_count; - ipd_ptr_count.u64 = cvmx_read_csr(CVMX_IPD_PTR_COUNT); - - /* Handle Work Queue Entry in cn56xx and cn52xx */ - if (octeon_has_feature(OCTEON_FEATURE_NO_WPTR)) { - union cvmx_ipd_ctl_status ipd_ctl_status; - ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); - if (ipd_ctl_status.s.no_wptr) - no_wptr = 1; - } - - /* Free the prefetched WQE */ - if (ipd_ptr_count.s.wqev_cnt) { - union cvmx_ipd_wqe_ptr_valid ipd_wqe_ptr_valid; - ipd_wqe_ptr_valid.u64 = - cvmx_read_csr(CVMX_IPD_WQE_PTR_VALID); - if (no_wptr) - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) ipd_wqe_ptr_valid.s. - ptr << 7), CVMX_FPA_PACKET_POOL, - 0); - else - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) ipd_wqe_ptr_valid.s. - ptr << 7), CVMX_FPA_WQE_POOL, 0); - } - - /* Free all WQE in the fifo */ - if (ipd_ptr_count.s.wqe_pcnt) { - int i; - union cvmx_ipd_pwp_ptr_fifo_ctl ipd_pwp_ptr_fifo_ctl; - ipd_pwp_ptr_fifo_ctl.u64 = - cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); - for (i = 0; i < ipd_ptr_count.s.wqe_pcnt; i++) { - ipd_pwp_ptr_fifo_ctl.s.cena = 0; - ipd_pwp_ptr_fifo_ctl.s.raddr = - ipd_pwp_ptr_fifo_ctl.s.max_cnts + - (ipd_pwp_ptr_fifo_ctl.s.wraddr + - i) % ipd_pwp_ptr_fifo_ctl.s.max_cnts; - cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, - ipd_pwp_ptr_fifo_ctl.u64); - ipd_pwp_ptr_fifo_ctl.u64 = - cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); - if (no_wptr) - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) - ipd_pwp_ptr_fifo_ctl.s. - ptr << 7), - CVMX_FPA_PACKET_POOL, 0); - else - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) - ipd_pwp_ptr_fifo_ctl.s. - ptr << 7), - CVMX_FPA_WQE_POOL, 0); - } - ipd_pwp_ptr_fifo_ctl.s.cena = 1; - cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, - ipd_pwp_ptr_fifo_ctl.u64); - } - - /* Free the prefetched packet */ - if (ipd_ptr_count.s.pktv_cnt) { - union cvmx_ipd_pkt_ptr_valid ipd_pkt_ptr_valid; - ipd_pkt_ptr_valid.u64 = - cvmx_read_csr(CVMX_IPD_PKT_PTR_VALID); - cvmx_fpa_free(cvmx_phys_to_ptr - (ipd_pkt_ptr_valid.s.ptr << 7), - CVMX_FPA_PACKET_POOL, 0); - } - - /* Free the per port prefetched packets */ - if (1) { - int i; - union cvmx_ipd_prc_port_ptr_fifo_ctl - ipd_prc_port_ptr_fifo_ctl; - ipd_prc_port_ptr_fifo_ctl.u64 = - cvmx_read_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL); - - for (i = 0; i < ipd_prc_port_ptr_fifo_ctl.s.max_pkt; - i++) { - ipd_prc_port_ptr_fifo_ctl.s.cena = 0; - ipd_prc_port_ptr_fifo_ctl.s.raddr = - i % ipd_prc_port_ptr_fifo_ctl.s.max_pkt; - cvmx_write_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL, - ipd_prc_port_ptr_fifo_ctl.u64); - ipd_prc_port_ptr_fifo_ctl.u64 = - cvmx_read_csr - (CVMX_IPD_PRC_PORT_PTR_FIFO_CTL); - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) - ipd_prc_port_ptr_fifo_ctl.s. - ptr << 7), CVMX_FPA_PACKET_POOL, - 0); - } - ipd_prc_port_ptr_fifo_ctl.s.cena = 1; - cvmx_write_csr(CVMX_IPD_PRC_PORT_PTR_FIFO_CTL, - ipd_prc_port_ptr_fifo_ctl.u64); - } - - /* Free all packets in the holding fifo */ - if (ipd_ptr_count.s.pfif_cnt) { - int i; - union cvmx_ipd_prc_hold_ptr_fifo_ctl - ipd_prc_hold_ptr_fifo_ctl; - - ipd_prc_hold_ptr_fifo_ctl.u64 = - cvmx_read_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL); - - for (i = 0; i < ipd_ptr_count.s.pfif_cnt; i++) { - ipd_prc_hold_ptr_fifo_ctl.s.cena = 0; - ipd_prc_hold_ptr_fifo_ctl.s.raddr = - (ipd_prc_hold_ptr_fifo_ctl.s.praddr + - i) % ipd_prc_hold_ptr_fifo_ctl.s.max_pkt; - cvmx_write_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL, - ipd_prc_hold_ptr_fifo_ctl.u64); - ipd_prc_hold_ptr_fifo_ctl.u64 = - cvmx_read_csr - (CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL); - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) - ipd_prc_hold_ptr_fifo_ctl.s. - ptr << 7), CVMX_FPA_PACKET_POOL, - 0); - } - ipd_prc_hold_ptr_fifo_ctl.s.cena = 1; - cvmx_write_csr(CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL, - ipd_prc_hold_ptr_fifo_ctl.u64); - } - - /* Free all packets in the fifo */ - if (ipd_ptr_count.s.pkt_pcnt) { - int i; - union cvmx_ipd_pwp_ptr_fifo_ctl ipd_pwp_ptr_fifo_ctl; - ipd_pwp_ptr_fifo_ctl.u64 = - cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); - - for (i = 0; i < ipd_ptr_count.s.pkt_pcnt; i++) { - ipd_pwp_ptr_fifo_ctl.s.cena = 0; - ipd_pwp_ptr_fifo_ctl.s.raddr = - (ipd_pwp_ptr_fifo_ctl.s.praddr + - i) % ipd_pwp_ptr_fifo_ctl.s.max_cnts; - cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, - ipd_pwp_ptr_fifo_ctl.u64); - ipd_pwp_ptr_fifo_ctl.u64 = - cvmx_read_csr(CVMX_IPD_PWP_PTR_FIFO_CTL); - cvmx_fpa_free(cvmx_phys_to_ptr - ((uint64_t) ipd_pwp_ptr_fifo_ctl. - s.ptr << 7), - CVMX_FPA_PACKET_POOL, 0); - } - ipd_pwp_ptr_fifo_ctl.s.cena = 1; - cvmx_write_csr(CVMX_IPD_PWP_PTR_FIFO_CTL, - ipd_pwp_ptr_fifo_ctl.u64); - } - - /* Reset the IPD to get all buffers out of it */ - { - union cvmx_ipd_ctl_status ipd_ctl_status; - ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); - ipd_ctl_status.s.reset = 1; - cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64); - } - - /* Reset the PIP */ - { - union cvmx_pip_sft_rst pip_sft_rst; - pip_sft_rst.u64 = cvmx_read_csr(CVMX_PIP_SFT_RST); - pip_sft_rst.s.rst = 1; - cvmx_write_csr(CVMX_PIP_SFT_RST, pip_sft_rst.u64); - } - } -} - -#endif /* __CVMX_IPD_H__ */ diff --git a/drivers/staging/octeon/cvmx-mdio.h b/drivers/staging/octeon/cvmx-mdio.h deleted file mode 100644 index d88ab8d8e37d..000000000000 --- a/drivers/staging/octeon/cvmx-mdio.h +++ /dev/null @@ -1,506 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Interface to the SMI/MDIO hardware, including support for both IEEE 802.3 - * clause 22 and clause 45 operations. - * - */ - -#ifndef __CVMX_MIO_H__ -#define __CVMX_MIO_H__ - -#include "cvmx-smix-defs.h" - -/** - * PHY register 0 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_CONTROL 0 -typedef union { - uint16_t u16; - struct { - uint16_t reset:1; - uint16_t loopback:1; - uint16_t speed_lsb:1; - uint16_t autoneg_enable:1; - uint16_t power_down:1; - uint16_t isolate:1; - uint16_t restart_autoneg:1; - uint16_t duplex:1; - uint16_t collision_test:1; - uint16_t speed_msb:1; - uint16_t unidirectional_enable:1; - uint16_t reserved_0_4:5; - } s; -} cvmx_mdio_phy_reg_control_t; - -/** - * PHY register 1 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_STATUS 1 -typedef union { - uint16_t u16; - struct { - uint16_t capable_100base_t4:1; - uint16_t capable_100base_x_full:1; - uint16_t capable_100base_x_half:1; - uint16_t capable_10_full:1; - uint16_t capable_10_half:1; - uint16_t capable_100base_t2_full:1; - uint16_t capable_100base_t2_half:1; - uint16_t capable_extended_status:1; - uint16_t capable_unidirectional:1; - uint16_t capable_mf_preamble_suppression:1; - uint16_t autoneg_complete:1; - uint16_t remote_fault:1; - uint16_t capable_autoneg:1; - uint16_t link_status:1; - uint16_t jabber_detect:1; - uint16_t capable_extended_registers:1; - - } s; -} cvmx_mdio_phy_reg_status_t; - -/** - * PHY register 2 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_ID1 2 -typedef union { - uint16_t u16; - struct { - uint16_t oui_bits_3_18; - } s; -} cvmx_mdio_phy_reg_id1_t; - -/** - * PHY register 3 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_ID2 3 -typedef union { - uint16_t u16; - struct { - uint16_t oui_bits_19_24:6; - uint16_t model:6; - uint16_t revision:4; - } s; -} cvmx_mdio_phy_reg_id2_t; - -/** - * PHY register 4 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_AUTONEG_ADVER 4 -typedef union { - uint16_t u16; - struct { - uint16_t next_page:1; - uint16_t reserved_14:1; - uint16_t remote_fault:1; - uint16_t reserved_12:1; - uint16_t asymmetric_pause:1; - uint16_t pause:1; - uint16_t advert_100base_t4:1; - uint16_t advert_100base_tx_full:1; - uint16_t advert_100base_tx_half:1; - uint16_t advert_10base_tx_full:1; - uint16_t advert_10base_tx_half:1; - uint16_t selector:5; - } s; -} cvmx_mdio_phy_reg_autoneg_adver_t; - -/** - * PHY register 5 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_LINK_PARTNER_ABILITY 5 -typedef union { - uint16_t u16; - struct { - uint16_t next_page:1; - uint16_t ack:1; - uint16_t remote_fault:1; - uint16_t reserved_12:1; - uint16_t asymmetric_pause:1; - uint16_t pause:1; - uint16_t advert_100base_t4:1; - uint16_t advert_100base_tx_full:1; - uint16_t advert_100base_tx_half:1; - uint16_t advert_10base_tx_full:1; - uint16_t advert_10base_tx_half:1; - uint16_t selector:5; - } s; -} cvmx_mdio_phy_reg_link_partner_ability_t; - -/** - * PHY register 6 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_AUTONEG_EXPANSION 6 -typedef union { - uint16_t u16; - struct { - uint16_t reserved_5_15:11; - uint16_t parallel_detection_fault:1; - uint16_t link_partner_next_page_capable:1; - uint16_t local_next_page_capable:1; - uint16_t page_received:1; - uint16_t link_partner_autoneg_capable:1; - - } s; -} cvmx_mdio_phy_reg_autoneg_expansion_t; - -/** - * PHY register 9 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_CONTROL_1000 9 -typedef union { - uint16_t u16; - struct { - uint16_t test_mode:3; - uint16_t manual_master_slave:1; - uint16_t master:1; - uint16_t port_type:1; - uint16_t advert_1000base_t_full:1; - uint16_t advert_1000base_t_half:1; - uint16_t reserved_0_7:8; - } s; -} cvmx_mdio_phy_reg_control_1000_t; - -/** - * PHY register 10 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_STATUS_1000 10 -typedef union { - uint16_t u16; - struct { - uint16_t master_slave_fault:1; - uint16_t is_master:1; - uint16_t local_receiver_ok:1; - uint16_t remote_receiver_ok:1; - uint16_t remote_capable_1000base_t_full:1; - uint16_t remote_capable_1000base_t_half:1; - uint16_t reserved_8_9:2; - uint16_t idle_error_count:8; - } s; -} cvmx_mdio_phy_reg_status_1000_t; - -/** - * PHY register 15 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_EXTENDED_STATUS 15 -typedef union { - uint16_t u16; - struct { - uint16_t capable_1000base_x_full:1; - uint16_t capable_1000base_x_half:1; - uint16_t capable_1000base_t_full:1; - uint16_t capable_1000base_t_half:1; - uint16_t reserved_0_11:12; - } s; -} cvmx_mdio_phy_reg_extended_status_t; - -/** - * PHY register 13 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_MMD_CONTROL 13 -typedef union { - uint16_t u16; - struct { - uint16_t function:2; - uint16_t reserved_5_13:9; - uint16_t devad:5; - } s; -} cvmx_mdio_phy_reg_mmd_control_t; - -/** - * PHY register 14 from the 802.3 spec - */ -#define CVMX_MDIO_PHY_REG_MMD_ADDRESS_DATA 14 -typedef union { - uint16_t u16; - struct { - uint16_t address_data:16; - } s; -} cvmx_mdio_phy_reg_mmd_address_data_t; - -/* Operating request encodings. */ -#define MDIO_CLAUSE_22_WRITE 0 -#define MDIO_CLAUSE_22_READ 1 - -#define MDIO_CLAUSE_45_ADDRESS 0 -#define MDIO_CLAUSE_45_WRITE 1 -#define MDIO_CLAUSE_45_READ_INC 2 -#define MDIO_CLAUSE_45_READ 3 - -/* MMD identifiers, mostly for accessing devices within XENPAK modules. */ -#define CVMX_MMD_DEVICE_PMA_PMD 1 -#define CVMX_MMD_DEVICE_WIS 2 -#define CVMX_MMD_DEVICE_PCS 3 -#define CVMX_MMD_DEVICE_PHY_XS 4 -#define CVMX_MMD_DEVICE_DTS_XS 5 -#define CVMX_MMD_DEVICE_TC 6 -#define CVMX_MMD_DEVICE_CL22_EXT 29 -#define CVMX_MMD_DEVICE_VENDOR_1 30 -#define CVMX_MMD_DEVICE_VENDOR_2 31 - -/* Helper function to put MDIO interface into clause 45 mode */ -static inline void __cvmx_mdio_set_clause45_mode(int bus_id) -{ - union cvmx_smix_clk smi_clk; - /* Put bus into clause 45 mode */ - smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); - smi_clk.s.mode = 1; - smi_clk.s.preamble = 1; - cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); -} - -/* Helper function to put MDIO interface into clause 22 mode */ -static inline void __cvmx_mdio_set_clause22_mode(int bus_id) -{ - union cvmx_smix_clk smi_clk; - /* Put bus into clause 22 mode */ - smi_clk.u64 = cvmx_read_csr(CVMX_SMIX_CLK(bus_id)); - smi_clk.s.mode = 0; - cvmx_write_csr(CVMX_SMIX_CLK(bus_id), smi_clk.u64); -} - -/** - * Perform an MII read. This function is used to read PHY - * registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @location: Register location to read - * - * Returns Result from the read or -1 on failure - */ -static inline int cvmx_mdio_read(int bus_id, int phy_id, int location) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_rd_dat smi_rd; - int timeout = 1000; - - if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - __cvmx_mdio_set_clause22_mode(bus_id); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_22_READ; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = location; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); - } while (smi_rd.s.pending && timeout--); - - if (smi_rd.s.val) - return smi_rd.s.dat; - else - return -1; -} - -/** - * Perform an MII write. This function is used to write PHY - * registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @location: Register location to write - * @val: Value to write - * - * Returns -1 on error - * 0 on success - */ -static inline int cvmx_mdio_write(int bus_id, int phy_id, int location, int val) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - if (octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - __cvmx_mdio_set_clause22_mode(bus_id); - - smi_wr.u64 = 0; - smi_wr.s.dat = val; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_22_WRITE; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = location; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) - return -1; - - return 0; -} - -/** - * Perform an IEEE 802.3 clause 45 MII read. This function is used to - * read PHY registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @device: MDIO Managable Device (MMD) id - * @location: Register location to read - * - * Returns Result from the read or -1 on failure - */ - -static inline int cvmx_mdio_45_read(int bus_id, int phy_id, int device, - int location) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_rd_dat smi_rd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - return -1; - - __cvmx_mdio_set_clause45_mode(bus_id); - - smi_wr.u64 = 0; - smi_wr.s.dat = location; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) { - cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " - "device %2d register %2d TIME OUT(address)\n", - bus_id, phy_id, device, location); - return -1; - } - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_READ; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(bus_id)); - } while (smi_rd.s.pending && --timeout); - - if (timeout <= 0) { - cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " - "device %2d register %2d TIME OUT(data)\n", - bus_id, phy_id, device, location); - return -1; - } - - if (smi_rd.s.val) - return smi_rd.s.dat; - else { - cvmx_dprintf("cvmx_mdio_45_read: bus_id %d phy_id %2d " - "device %2d register %2d INVALID READ\n", - bus_id, phy_id, device, location); - return -1; - } -} - -/** - * Perform an IEEE 802.3 clause 45 MII write. This function is used to - * write PHY registers controlling auto negotiation. - * - * @bus_id: MDIO bus number. Zero on most chips, but some chips (ex CN56XX) - * support multiple busses. - * @phy_id: The MII phy id - * @device: MDIO Managable Device (MMD) id - * @location: Register location to write - * @val: Value to write - * - * Returns -1 on error - * 0 on success - */ -static inline int cvmx_mdio_45_write(int bus_id, int phy_id, int device, - int location, int val) -{ - union cvmx_smix_cmd smi_cmd; - union cvmx_smix_wr_dat smi_wr; - int timeout = 1000; - - if (!octeon_has_feature(OCTEON_FEATURE_MDIO_CLAUSE_45)) - return -1; - - __cvmx_mdio_set_clause45_mode(bus_id); - - smi_wr.u64 = 0; - smi_wr.s.dat = location; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_ADDRESS; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) - return -1; - - smi_wr.u64 = 0; - smi_wr.s.dat = val; - cvmx_write_csr(CVMX_SMIX_WR_DAT(bus_id), smi_wr.u64); - - smi_cmd.u64 = 0; - smi_cmd.s.phy_op = MDIO_CLAUSE_45_WRITE; - smi_cmd.s.phy_adr = phy_id; - smi_cmd.s.reg_adr = device; - cvmx_write_csr(CVMX_SMIX_CMD(bus_id), smi_cmd.u64); - - do { - cvmx_wait(1000); - smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(bus_id)); - } while (smi_wr.s.pending && --timeout); - if (timeout <= 0) - return -1; - - return 0; -} - -#endif diff --git a/drivers/staging/octeon/cvmx-packet.h b/drivers/staging/octeon/cvmx-packet.h deleted file mode 100644 index 62ffe78a8c81..000000000000 --- a/drivers/staging/octeon/cvmx-packet.h +++ /dev/null @@ -1,65 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * Packet buffer defines. - */ - -#ifndef __CVMX_PACKET_H__ -#define __CVMX_PACKET_H__ - -/** - * This structure defines a buffer pointer on Octeon - */ -union cvmx_buf_ptr { - void *ptr; - uint64_t u64; - struct { - /* - * if set, invert the "free" pick of the overall - * packet. HW always sets this bit to 0 on inbound - * packet - */ - uint64_t i:1; - /* - * Indicates the amount to back up to get to the - * buffer start in cache lines. In most cases this is - * less than one complete cache line, so the value is - * zero. - */ - uint64_t back:4; - /* The pool that the buffer came from / goes to */ - uint64_t pool:3; - /* The size of the segment pointed to by addr (in bytes) */ - uint64_t size:16; - /* Pointer to the first byte of the data, NOT buffer */ - uint64_t addr:40; - } s; -}; - -#endif /* __CVMX_PACKET_H__ */ diff --git a/drivers/staging/octeon/cvmx-pcsx-defs.h b/drivers/staging/octeon/cvmx-pcsx-defs.h deleted file mode 100644 index d45952df5f5b..000000000000 --- a/drivers/staging/octeon/cvmx-pcsx-defs.h +++ /dev/null @@ -1,370 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_PCSX_DEFS_H__ -#define __CVMX_PCSX_DEFS_H__ - -#define CVMX_PCSX_ANX_ADV_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001010ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_ANX_EXT_ST_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001028ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_ANX_LP_ABIL_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001018ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_ANX_RESULTS_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001020ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_INTX_EN_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001088ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_INTX_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001080ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_LINKX_TIMER_COUNT_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001040ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_LOG_ANLX_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001090ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_MISCX_CTL_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001078ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_MRX_CONTROL_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001000ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_MRX_STATUS_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001008ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_RXX_STATES_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001058ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_RXX_SYNC_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001050ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_SGMX_AN_ADV_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001068ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_SGMX_LP_ADV_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001070ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_TXX_STATES_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001060ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSX_TX_RXX_POLARITY_REG(offset, block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0001048ull + (((offset) & 3) * 1024) + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_pcsx_anx_adv_reg { - uint64_t u64; - struct cvmx_pcsx_anx_adv_reg_s { - uint64_t reserved_16_63:48; - uint64_t np:1; - uint64_t reserved_14_14:1; - uint64_t rem_flt:2; - uint64_t reserved_9_11:3; - uint64_t pause:2; - uint64_t hfd:1; - uint64_t fd:1; - uint64_t reserved_0_4:5; - } s; - struct cvmx_pcsx_anx_adv_reg_s cn52xx; - struct cvmx_pcsx_anx_adv_reg_s cn52xxp1; - struct cvmx_pcsx_anx_adv_reg_s cn56xx; - struct cvmx_pcsx_anx_adv_reg_s cn56xxp1; -}; - -union cvmx_pcsx_anx_ext_st_reg { - uint64_t u64; - struct cvmx_pcsx_anx_ext_st_reg_s { - uint64_t reserved_16_63:48; - uint64_t thou_xfd:1; - uint64_t thou_xhd:1; - uint64_t thou_tfd:1; - uint64_t thou_thd:1; - uint64_t reserved_0_11:12; - } s; - struct cvmx_pcsx_anx_ext_st_reg_s cn52xx; - struct cvmx_pcsx_anx_ext_st_reg_s cn52xxp1; - struct cvmx_pcsx_anx_ext_st_reg_s cn56xx; - struct cvmx_pcsx_anx_ext_st_reg_s cn56xxp1; -}; - -union cvmx_pcsx_anx_lp_abil_reg { - uint64_t u64; - struct cvmx_pcsx_anx_lp_abil_reg_s { - uint64_t reserved_16_63:48; - uint64_t np:1; - uint64_t ack:1; - uint64_t rem_flt:2; - uint64_t reserved_9_11:3; - uint64_t pause:2; - uint64_t hfd:1; - uint64_t fd:1; - uint64_t reserved_0_4:5; - } s; - struct cvmx_pcsx_anx_lp_abil_reg_s cn52xx; - struct cvmx_pcsx_anx_lp_abil_reg_s cn52xxp1; - struct cvmx_pcsx_anx_lp_abil_reg_s cn56xx; - struct cvmx_pcsx_anx_lp_abil_reg_s cn56xxp1; -}; - -union cvmx_pcsx_anx_results_reg { - uint64_t u64; - struct cvmx_pcsx_anx_results_reg_s { - uint64_t reserved_7_63:57; - uint64_t pause:2; - uint64_t spd:2; - uint64_t an_cpt:1; - uint64_t dup:1; - uint64_t link_ok:1; - } s; - struct cvmx_pcsx_anx_results_reg_s cn52xx; - struct cvmx_pcsx_anx_results_reg_s cn52xxp1; - struct cvmx_pcsx_anx_results_reg_s cn56xx; - struct cvmx_pcsx_anx_results_reg_s cn56xxp1; -}; - -union cvmx_pcsx_intx_en_reg { - uint64_t u64; - struct cvmx_pcsx_intx_en_reg_s { - uint64_t reserved_12_63:52; - uint64_t dup:1; - uint64_t sync_bad_en:1; - uint64_t an_bad_en:1; - uint64_t rxlock_en:1; - uint64_t rxbad_en:1; - uint64_t rxerr_en:1; - uint64_t txbad_en:1; - uint64_t txfifo_en:1; - uint64_t txfifu_en:1; - uint64_t an_err_en:1; - uint64_t xmit_en:1; - uint64_t lnkspd_en:1; - } s; - struct cvmx_pcsx_intx_en_reg_s cn52xx; - struct cvmx_pcsx_intx_en_reg_s cn52xxp1; - struct cvmx_pcsx_intx_en_reg_s cn56xx; - struct cvmx_pcsx_intx_en_reg_s cn56xxp1; -}; - -union cvmx_pcsx_intx_reg { - uint64_t u64; - struct cvmx_pcsx_intx_reg_s { - uint64_t reserved_12_63:52; - uint64_t dup:1; - uint64_t sync_bad:1; - uint64_t an_bad:1; - uint64_t rxlock:1; - uint64_t rxbad:1; - uint64_t rxerr:1; - uint64_t txbad:1; - uint64_t txfifo:1; - uint64_t txfifu:1; - uint64_t an_err:1; - uint64_t xmit:1; - uint64_t lnkspd:1; - } s; - struct cvmx_pcsx_intx_reg_s cn52xx; - struct cvmx_pcsx_intx_reg_s cn52xxp1; - struct cvmx_pcsx_intx_reg_s cn56xx; - struct cvmx_pcsx_intx_reg_s cn56xxp1; -}; - -union cvmx_pcsx_linkx_timer_count_reg { - uint64_t u64; - struct cvmx_pcsx_linkx_timer_count_reg_s { - uint64_t reserved_16_63:48; - uint64_t count:16; - } s; - struct cvmx_pcsx_linkx_timer_count_reg_s cn52xx; - struct cvmx_pcsx_linkx_timer_count_reg_s cn52xxp1; - struct cvmx_pcsx_linkx_timer_count_reg_s cn56xx; - struct cvmx_pcsx_linkx_timer_count_reg_s cn56xxp1; -}; - -union cvmx_pcsx_log_anlx_reg { - uint64_t u64; - struct cvmx_pcsx_log_anlx_reg_s { - uint64_t reserved_4_63:60; - uint64_t lafifovfl:1; - uint64_t la_en:1; - uint64_t pkt_sz:2; - } s; - struct cvmx_pcsx_log_anlx_reg_s cn52xx; - struct cvmx_pcsx_log_anlx_reg_s cn52xxp1; - struct cvmx_pcsx_log_anlx_reg_s cn56xx; - struct cvmx_pcsx_log_anlx_reg_s cn56xxp1; -}; - -union cvmx_pcsx_miscx_ctl_reg { - uint64_t u64; - struct cvmx_pcsx_miscx_ctl_reg_s { - uint64_t reserved_13_63:51; - uint64_t sgmii:1; - uint64_t gmxeno:1; - uint64_t loopbck2:1; - uint64_t mac_phy:1; - uint64_t mode:1; - uint64_t an_ovrd:1; - uint64_t samp_pt:7; - } s; - struct cvmx_pcsx_miscx_ctl_reg_s cn52xx; - struct cvmx_pcsx_miscx_ctl_reg_s cn52xxp1; - struct cvmx_pcsx_miscx_ctl_reg_s cn56xx; - struct cvmx_pcsx_miscx_ctl_reg_s cn56xxp1; -}; - -union cvmx_pcsx_mrx_control_reg { - uint64_t u64; - struct cvmx_pcsx_mrx_control_reg_s { - uint64_t reserved_16_63:48; - uint64_t reset:1; - uint64_t loopbck1:1; - uint64_t spdlsb:1; - uint64_t an_en:1; - uint64_t pwr_dn:1; - uint64_t reserved_10_10:1; - uint64_t rst_an:1; - uint64_t dup:1; - uint64_t coltst:1; - uint64_t spdmsb:1; - uint64_t uni:1; - uint64_t reserved_0_4:5; - } s; - struct cvmx_pcsx_mrx_control_reg_s cn52xx; - struct cvmx_pcsx_mrx_control_reg_s cn52xxp1; - struct cvmx_pcsx_mrx_control_reg_s cn56xx; - struct cvmx_pcsx_mrx_control_reg_s cn56xxp1; -}; - -union cvmx_pcsx_mrx_status_reg { - uint64_t u64; - struct cvmx_pcsx_mrx_status_reg_s { - uint64_t reserved_16_63:48; - uint64_t hun_t4:1; - uint64_t hun_xfd:1; - uint64_t hun_xhd:1; - uint64_t ten_fd:1; - uint64_t ten_hd:1; - uint64_t hun_t2fd:1; - uint64_t hun_t2hd:1; - uint64_t ext_st:1; - uint64_t reserved_7_7:1; - uint64_t prb_sup:1; - uint64_t an_cpt:1; - uint64_t rm_flt:1; - uint64_t an_abil:1; - uint64_t lnk_st:1; - uint64_t reserved_1_1:1; - uint64_t extnd:1; - } s; - struct cvmx_pcsx_mrx_status_reg_s cn52xx; - struct cvmx_pcsx_mrx_status_reg_s cn52xxp1; - struct cvmx_pcsx_mrx_status_reg_s cn56xx; - struct cvmx_pcsx_mrx_status_reg_s cn56xxp1; -}; - -union cvmx_pcsx_rxx_states_reg { - uint64_t u64; - struct cvmx_pcsx_rxx_states_reg_s { - uint64_t reserved_16_63:48; - uint64_t rx_bad:1; - uint64_t rx_st:5; - uint64_t sync_bad:1; - uint64_t sync:4; - uint64_t an_bad:1; - uint64_t an_st:4; - } s; - struct cvmx_pcsx_rxx_states_reg_s cn52xx; - struct cvmx_pcsx_rxx_states_reg_s cn52xxp1; - struct cvmx_pcsx_rxx_states_reg_s cn56xx; - struct cvmx_pcsx_rxx_states_reg_s cn56xxp1; -}; - -union cvmx_pcsx_rxx_sync_reg { - uint64_t u64; - struct cvmx_pcsx_rxx_sync_reg_s { - uint64_t reserved_2_63:62; - uint64_t sync:1; - uint64_t bit_lock:1; - } s; - struct cvmx_pcsx_rxx_sync_reg_s cn52xx; - struct cvmx_pcsx_rxx_sync_reg_s cn52xxp1; - struct cvmx_pcsx_rxx_sync_reg_s cn56xx; - struct cvmx_pcsx_rxx_sync_reg_s cn56xxp1; -}; - -union cvmx_pcsx_sgmx_an_adv_reg { - uint64_t u64; - struct cvmx_pcsx_sgmx_an_adv_reg_s { - uint64_t reserved_16_63:48; - uint64_t link:1; - uint64_t ack:1; - uint64_t reserved_13_13:1; - uint64_t dup:1; - uint64_t speed:2; - uint64_t reserved_1_9:9; - uint64_t one:1; - } s; - struct cvmx_pcsx_sgmx_an_adv_reg_s cn52xx; - struct cvmx_pcsx_sgmx_an_adv_reg_s cn52xxp1; - struct cvmx_pcsx_sgmx_an_adv_reg_s cn56xx; - struct cvmx_pcsx_sgmx_an_adv_reg_s cn56xxp1; -}; - -union cvmx_pcsx_sgmx_lp_adv_reg { - uint64_t u64; - struct cvmx_pcsx_sgmx_lp_adv_reg_s { - uint64_t reserved_16_63:48; - uint64_t link:1; - uint64_t reserved_13_14:2; - uint64_t dup:1; - uint64_t speed:2; - uint64_t reserved_1_9:9; - uint64_t one:1; - } s; - struct cvmx_pcsx_sgmx_lp_adv_reg_s cn52xx; - struct cvmx_pcsx_sgmx_lp_adv_reg_s cn52xxp1; - struct cvmx_pcsx_sgmx_lp_adv_reg_s cn56xx; - struct cvmx_pcsx_sgmx_lp_adv_reg_s cn56xxp1; -}; - -union cvmx_pcsx_txx_states_reg { - uint64_t u64; - struct cvmx_pcsx_txx_states_reg_s { - uint64_t reserved_7_63:57; - uint64_t xmit:2; - uint64_t tx_bad:1; - uint64_t ord_st:4; - } s; - struct cvmx_pcsx_txx_states_reg_s cn52xx; - struct cvmx_pcsx_txx_states_reg_s cn52xxp1; - struct cvmx_pcsx_txx_states_reg_s cn56xx; - struct cvmx_pcsx_txx_states_reg_s cn56xxp1; -}; - -union cvmx_pcsx_tx_rxx_polarity_reg { - uint64_t u64; - struct cvmx_pcsx_tx_rxx_polarity_reg_s { - uint64_t reserved_4_63:60; - uint64_t rxovrd:1; - uint64_t autorxpl:1; - uint64_t rxplrt:1; - uint64_t txplrt:1; - } s; - struct cvmx_pcsx_tx_rxx_polarity_reg_s cn52xx; - struct cvmx_pcsx_tx_rxx_polarity_reg_s cn52xxp1; - struct cvmx_pcsx_tx_rxx_polarity_reg_s cn56xx; - struct cvmx_pcsx_tx_rxx_polarity_reg_s cn56xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-pcsxx-defs.h b/drivers/staging/octeon/cvmx-pcsxx-defs.h deleted file mode 100644 index 55d120fe8aed..000000000000 --- a/drivers/staging/octeon/cvmx-pcsxx-defs.h +++ /dev/null @@ -1,316 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_PCSXX_DEFS_H__ -#define __CVMX_PCSXX_DEFS_H__ - -#define CVMX_PCSXX_10GBX_STATUS_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000828ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_BIST_STATUS_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000870ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_BIT_LOCK_STATUS_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000850ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_CONTROL1_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000800ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_CONTROL2_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000818ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_INT_EN_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000860ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_INT_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000858ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_LOG_ANL_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000868ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_MISC_CTL_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000848ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_RX_SYNC_STATES_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000838ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_SPD_ABIL_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000810ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_STATUS1_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000808ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_STATUS2_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000820ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_TX_RX_POLARITY_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000840ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_PCSXX_TX_RX_STATES_REG(block_id) \ - CVMX_ADD_IO_SEG(0x00011800B0000830ull + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_pcsxx_10gbx_status_reg { - uint64_t u64; - struct cvmx_pcsxx_10gbx_status_reg_s { - uint64_t reserved_13_63:51; - uint64_t alignd:1; - uint64_t pattst:1; - uint64_t reserved_4_10:7; - uint64_t l3sync:1; - uint64_t l2sync:1; - uint64_t l1sync:1; - uint64_t l0sync:1; - } s; - struct cvmx_pcsxx_10gbx_status_reg_s cn52xx; - struct cvmx_pcsxx_10gbx_status_reg_s cn52xxp1; - struct cvmx_pcsxx_10gbx_status_reg_s cn56xx; - struct cvmx_pcsxx_10gbx_status_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_bist_status_reg { - uint64_t u64; - struct cvmx_pcsxx_bist_status_reg_s { - uint64_t reserved_1_63:63; - uint64_t bist_status:1; - } s; - struct cvmx_pcsxx_bist_status_reg_s cn52xx; - struct cvmx_pcsxx_bist_status_reg_s cn52xxp1; - struct cvmx_pcsxx_bist_status_reg_s cn56xx; - struct cvmx_pcsxx_bist_status_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_bit_lock_status_reg { - uint64_t u64; - struct cvmx_pcsxx_bit_lock_status_reg_s { - uint64_t reserved_4_63:60; - uint64_t bitlck3:1; - uint64_t bitlck2:1; - uint64_t bitlck1:1; - uint64_t bitlck0:1; - } s; - struct cvmx_pcsxx_bit_lock_status_reg_s cn52xx; - struct cvmx_pcsxx_bit_lock_status_reg_s cn52xxp1; - struct cvmx_pcsxx_bit_lock_status_reg_s cn56xx; - struct cvmx_pcsxx_bit_lock_status_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_control1_reg { - uint64_t u64; - struct cvmx_pcsxx_control1_reg_s { - uint64_t reserved_16_63:48; - uint64_t reset:1; - uint64_t loopbck1:1; - uint64_t spdsel1:1; - uint64_t reserved_12_12:1; - uint64_t lo_pwr:1; - uint64_t reserved_7_10:4; - uint64_t spdsel0:1; - uint64_t spd:4; - uint64_t reserved_0_1:2; - } s; - struct cvmx_pcsxx_control1_reg_s cn52xx; - struct cvmx_pcsxx_control1_reg_s cn52xxp1; - struct cvmx_pcsxx_control1_reg_s cn56xx; - struct cvmx_pcsxx_control1_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_control2_reg { - uint64_t u64; - struct cvmx_pcsxx_control2_reg_s { - uint64_t reserved_2_63:62; - uint64_t type:2; - } s; - struct cvmx_pcsxx_control2_reg_s cn52xx; - struct cvmx_pcsxx_control2_reg_s cn52xxp1; - struct cvmx_pcsxx_control2_reg_s cn56xx; - struct cvmx_pcsxx_control2_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_int_en_reg { - uint64_t u64; - struct cvmx_pcsxx_int_en_reg_s { - uint64_t reserved_6_63:58; - uint64_t algnlos_en:1; - uint64_t synlos_en:1; - uint64_t bitlckls_en:1; - uint64_t rxsynbad_en:1; - uint64_t rxbad_en:1; - uint64_t txflt_en:1; - } s; - struct cvmx_pcsxx_int_en_reg_s cn52xx; - struct cvmx_pcsxx_int_en_reg_s cn52xxp1; - struct cvmx_pcsxx_int_en_reg_s cn56xx; - struct cvmx_pcsxx_int_en_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_int_reg { - uint64_t u64; - struct cvmx_pcsxx_int_reg_s { - uint64_t reserved_6_63:58; - uint64_t algnlos:1; - uint64_t synlos:1; - uint64_t bitlckls:1; - uint64_t rxsynbad:1; - uint64_t rxbad:1; - uint64_t txflt:1; - } s; - struct cvmx_pcsxx_int_reg_s cn52xx; - struct cvmx_pcsxx_int_reg_s cn52xxp1; - struct cvmx_pcsxx_int_reg_s cn56xx; - struct cvmx_pcsxx_int_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_log_anl_reg { - uint64_t u64; - struct cvmx_pcsxx_log_anl_reg_s { - uint64_t reserved_7_63:57; - uint64_t enc_mode:1; - uint64_t drop_ln:2; - uint64_t lafifovfl:1; - uint64_t la_en:1; - uint64_t pkt_sz:2; - } s; - struct cvmx_pcsxx_log_anl_reg_s cn52xx; - struct cvmx_pcsxx_log_anl_reg_s cn52xxp1; - struct cvmx_pcsxx_log_anl_reg_s cn56xx; - struct cvmx_pcsxx_log_anl_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_misc_ctl_reg { - uint64_t u64; - struct cvmx_pcsxx_misc_ctl_reg_s { - uint64_t reserved_4_63:60; - uint64_t tx_swap:1; - uint64_t rx_swap:1; - uint64_t xaui:1; - uint64_t gmxeno:1; - } s; - struct cvmx_pcsxx_misc_ctl_reg_s cn52xx; - struct cvmx_pcsxx_misc_ctl_reg_s cn52xxp1; - struct cvmx_pcsxx_misc_ctl_reg_s cn56xx; - struct cvmx_pcsxx_misc_ctl_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_rx_sync_states_reg { - uint64_t u64; - struct cvmx_pcsxx_rx_sync_states_reg_s { - uint64_t reserved_16_63:48; - uint64_t sync3st:4; - uint64_t sync2st:4; - uint64_t sync1st:4; - uint64_t sync0st:4; - } s; - struct cvmx_pcsxx_rx_sync_states_reg_s cn52xx; - struct cvmx_pcsxx_rx_sync_states_reg_s cn52xxp1; - struct cvmx_pcsxx_rx_sync_states_reg_s cn56xx; - struct cvmx_pcsxx_rx_sync_states_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_spd_abil_reg { - uint64_t u64; - struct cvmx_pcsxx_spd_abil_reg_s { - uint64_t reserved_2_63:62; - uint64_t tenpasst:1; - uint64_t tengb:1; - } s; - struct cvmx_pcsxx_spd_abil_reg_s cn52xx; - struct cvmx_pcsxx_spd_abil_reg_s cn52xxp1; - struct cvmx_pcsxx_spd_abil_reg_s cn56xx; - struct cvmx_pcsxx_spd_abil_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_status1_reg { - uint64_t u64; - struct cvmx_pcsxx_status1_reg_s { - uint64_t reserved_8_63:56; - uint64_t flt:1; - uint64_t reserved_3_6:4; - uint64_t rcv_lnk:1; - uint64_t lpable:1; - uint64_t reserved_0_0:1; - } s; - struct cvmx_pcsxx_status1_reg_s cn52xx; - struct cvmx_pcsxx_status1_reg_s cn52xxp1; - struct cvmx_pcsxx_status1_reg_s cn56xx; - struct cvmx_pcsxx_status1_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_status2_reg { - uint64_t u64; - struct cvmx_pcsxx_status2_reg_s { - uint64_t reserved_16_63:48; - uint64_t dev:2; - uint64_t reserved_12_13:2; - uint64_t xmtflt:1; - uint64_t rcvflt:1; - uint64_t reserved_3_9:7; - uint64_t tengb_w:1; - uint64_t tengb_x:1; - uint64_t tengb_r:1; - } s; - struct cvmx_pcsxx_status2_reg_s cn52xx; - struct cvmx_pcsxx_status2_reg_s cn52xxp1; - struct cvmx_pcsxx_status2_reg_s cn56xx; - struct cvmx_pcsxx_status2_reg_s cn56xxp1; -}; - -union cvmx_pcsxx_tx_rx_polarity_reg { - uint64_t u64; - struct cvmx_pcsxx_tx_rx_polarity_reg_s { - uint64_t reserved_10_63:54; - uint64_t xor_rxplrt:4; - uint64_t xor_txplrt:4; - uint64_t rxplrt:1; - uint64_t txplrt:1; - } s; - struct cvmx_pcsxx_tx_rx_polarity_reg_s cn52xx; - struct cvmx_pcsxx_tx_rx_polarity_reg_cn52xxp1 { - uint64_t reserved_2_63:62; - uint64_t rxplrt:1; - uint64_t txplrt:1; - } cn52xxp1; - struct cvmx_pcsxx_tx_rx_polarity_reg_s cn56xx; - struct cvmx_pcsxx_tx_rx_polarity_reg_cn52xxp1 cn56xxp1; -}; - -union cvmx_pcsxx_tx_rx_states_reg { - uint64_t u64; - struct cvmx_pcsxx_tx_rx_states_reg_s { - uint64_t reserved_14_63:50; - uint64_t term_err:1; - uint64_t syn3bad:1; - uint64_t syn2bad:1; - uint64_t syn1bad:1; - uint64_t syn0bad:1; - uint64_t rxbad:1; - uint64_t algn_st:3; - uint64_t rx_st:2; - uint64_t tx_st:3; - } s; - struct cvmx_pcsxx_tx_rx_states_reg_s cn52xx; - struct cvmx_pcsxx_tx_rx_states_reg_cn52xxp1 { - uint64_t reserved_13_63:51; - uint64_t syn3bad:1; - uint64_t syn2bad:1; - uint64_t syn1bad:1; - uint64_t syn0bad:1; - uint64_t rxbad:1; - uint64_t algn_st:3; - uint64_t rx_st:2; - uint64_t tx_st:3; - } cn52xxp1; - struct cvmx_pcsxx_tx_rx_states_reg_s cn56xx; - struct cvmx_pcsxx_tx_rx_states_reg_cn52xxp1 cn56xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-pip-defs.h b/drivers/staging/octeon/cvmx-pip-defs.h deleted file mode 100644 index 5a369100ca68..000000000000 --- a/drivers/staging/octeon/cvmx-pip-defs.h +++ /dev/null @@ -1,1267 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_PIP_DEFS_H__ -#define __CVMX_PIP_DEFS_H__ - -/* - * Enumeration representing the amount of packet processing - * and validation performed by the input hardware. - */ -enum cvmx_pip_port_parse_mode { - /* - * Packet input doesn't perform any processing of the input - * packet. - */ - CVMX_PIP_PORT_CFG_MODE_NONE = 0ull, - /* - * Full packet processing is performed with pointer starting - * at the L2 (ethernet MAC) header. - */ - CVMX_PIP_PORT_CFG_MODE_SKIPL2 = 1ull, - /* - * Input packets are assumed to be IP. Results from non IP - * packets is undefined. Pointers reference the beginning of - * the IP header. - */ - CVMX_PIP_PORT_CFG_MODE_SKIPIP = 2ull -}; - -#define CVMX_PIP_BCK_PRS \ - CVMX_ADD_IO_SEG(0x00011800A0000038ull) -#define CVMX_PIP_BIST_STATUS \ - CVMX_ADD_IO_SEG(0x00011800A0000000ull) -#define CVMX_PIP_CRC_CTLX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000040ull + (((offset) & 1) * 8)) -#define CVMX_PIP_CRC_IVX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000050ull + (((offset) & 1) * 8)) -#define CVMX_PIP_DEC_IPSECX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000080ull + (((offset) & 3) * 8)) -#define CVMX_PIP_DSA_SRC_GRP \ - CVMX_ADD_IO_SEG(0x00011800A0000190ull) -#define CVMX_PIP_DSA_VID_GRP \ - CVMX_ADD_IO_SEG(0x00011800A0000198ull) -#define CVMX_PIP_FRM_LEN_CHKX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000180ull + (((offset) & 1) * 8)) -#define CVMX_PIP_GBL_CFG \ - CVMX_ADD_IO_SEG(0x00011800A0000028ull) -#define CVMX_PIP_GBL_CTL \ - CVMX_ADD_IO_SEG(0x00011800A0000020ull) -#define CVMX_PIP_HG_PRI_QOS \ - CVMX_ADD_IO_SEG(0x00011800A00001A0ull) -#define CVMX_PIP_INT_EN \ - CVMX_ADD_IO_SEG(0x00011800A0000010ull) -#define CVMX_PIP_INT_REG \ - CVMX_ADD_IO_SEG(0x00011800A0000008ull) -#define CVMX_PIP_IP_OFFSET \ - CVMX_ADD_IO_SEG(0x00011800A0000060ull) -#define CVMX_PIP_PRT_CFGX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000200ull + (((offset) & 63) * 8)) -#define CVMX_PIP_PRT_TAGX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000400ull + (((offset) & 63) * 8)) -#define CVMX_PIP_QOS_DIFFX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000600ull + (((offset) & 63) * 8)) -#define CVMX_PIP_QOS_VLANX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A00000C0ull + (((offset) & 7) * 8)) -#define CVMX_PIP_QOS_WATCHX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000100ull + (((offset) & 7) * 8)) -#define CVMX_PIP_RAW_WORD \ - CVMX_ADD_IO_SEG(0x00011800A00000B0ull) -#define CVMX_PIP_SFT_RST \ - CVMX_ADD_IO_SEG(0x00011800A0000030ull) -#define CVMX_PIP_STAT0_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000800ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT1_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000808ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT2_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000810ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT3_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000818ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT4_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000820ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT5_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000828ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT6_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000830ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT7_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000838ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT8_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000840ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT9_PRTX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0000848ull + (((offset) & 63) * 80)) -#define CVMX_PIP_STAT_CTL \ - CVMX_ADD_IO_SEG(0x00011800A0000018ull) -#define CVMX_PIP_STAT_INB_ERRSX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0001A10ull + (((offset) & 63) * 32)) -#define CVMX_PIP_STAT_INB_OCTSX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0001A08ull + (((offset) & 63) * 32)) -#define CVMX_PIP_STAT_INB_PKTSX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0001A00ull + (((offset) & 63) * 32)) -#define CVMX_PIP_TAG_INCX(offset) \ - CVMX_ADD_IO_SEG(0x00011800A0001800ull + (((offset) & 63) * 8)) -#define CVMX_PIP_TAG_MASK \ - CVMX_ADD_IO_SEG(0x00011800A0000070ull) -#define CVMX_PIP_TAG_SECRET \ - CVMX_ADD_IO_SEG(0x00011800A0000068ull) -#define CVMX_PIP_TODO_ENTRY \ - CVMX_ADD_IO_SEG(0x00011800A0000078ull) - -union cvmx_pip_bck_prs { - uint64_t u64; - struct cvmx_pip_bck_prs_s { - uint64_t bckprs:1; - uint64_t reserved_13_62:50; - uint64_t hiwater:5; - uint64_t reserved_5_7:3; - uint64_t lowater:5; - } s; - struct cvmx_pip_bck_prs_s cn38xx; - struct cvmx_pip_bck_prs_s cn38xxp2; - struct cvmx_pip_bck_prs_s cn56xx; - struct cvmx_pip_bck_prs_s cn56xxp1; - struct cvmx_pip_bck_prs_s cn58xx; - struct cvmx_pip_bck_prs_s cn58xxp1; -}; - -union cvmx_pip_bist_status { - uint64_t u64; - struct cvmx_pip_bist_status_s { - uint64_t reserved_18_63:46; - uint64_t bist:18; - } s; - struct cvmx_pip_bist_status_s cn30xx; - struct cvmx_pip_bist_status_s cn31xx; - struct cvmx_pip_bist_status_s cn38xx; - struct cvmx_pip_bist_status_s cn38xxp2; - struct cvmx_pip_bist_status_cn50xx { - uint64_t reserved_17_63:47; - uint64_t bist:17; - } cn50xx; - struct cvmx_pip_bist_status_s cn52xx; - struct cvmx_pip_bist_status_s cn52xxp1; - struct cvmx_pip_bist_status_s cn56xx; - struct cvmx_pip_bist_status_s cn56xxp1; - struct cvmx_pip_bist_status_s cn58xx; - struct cvmx_pip_bist_status_s cn58xxp1; -}; - -union cvmx_pip_crc_ctlx { - uint64_t u64; - struct cvmx_pip_crc_ctlx_s { - uint64_t reserved_2_63:62; - uint64_t invres:1; - uint64_t reflect:1; - } s; - struct cvmx_pip_crc_ctlx_s cn38xx; - struct cvmx_pip_crc_ctlx_s cn38xxp2; - struct cvmx_pip_crc_ctlx_s cn58xx; - struct cvmx_pip_crc_ctlx_s cn58xxp1; -}; - -union cvmx_pip_crc_ivx { - uint64_t u64; - struct cvmx_pip_crc_ivx_s { - uint64_t reserved_32_63:32; - uint64_t iv:32; - } s; - struct cvmx_pip_crc_ivx_s cn38xx; - struct cvmx_pip_crc_ivx_s cn38xxp2; - struct cvmx_pip_crc_ivx_s cn58xx; - struct cvmx_pip_crc_ivx_s cn58xxp1; -}; - -union cvmx_pip_dec_ipsecx { - uint64_t u64; - struct cvmx_pip_dec_ipsecx_s { - uint64_t reserved_18_63:46; - uint64_t tcp:1; - uint64_t udp:1; - uint64_t dprt:16; - } s; - struct cvmx_pip_dec_ipsecx_s cn30xx; - struct cvmx_pip_dec_ipsecx_s cn31xx; - struct cvmx_pip_dec_ipsecx_s cn38xx; - struct cvmx_pip_dec_ipsecx_s cn38xxp2; - struct cvmx_pip_dec_ipsecx_s cn50xx; - struct cvmx_pip_dec_ipsecx_s cn52xx; - struct cvmx_pip_dec_ipsecx_s cn52xxp1; - struct cvmx_pip_dec_ipsecx_s cn56xx; - struct cvmx_pip_dec_ipsecx_s cn56xxp1; - struct cvmx_pip_dec_ipsecx_s cn58xx; - struct cvmx_pip_dec_ipsecx_s cn58xxp1; -}; - -union cvmx_pip_dsa_src_grp { - uint64_t u64; - struct cvmx_pip_dsa_src_grp_s { - uint64_t map15:4; - uint64_t map14:4; - uint64_t map13:4; - uint64_t map12:4; - uint64_t map11:4; - uint64_t map10:4; - uint64_t map9:4; - uint64_t map8:4; - uint64_t map7:4; - uint64_t map6:4; - uint64_t map5:4; - uint64_t map4:4; - uint64_t map3:4; - uint64_t map2:4; - uint64_t map1:4; - uint64_t map0:4; - } s; - struct cvmx_pip_dsa_src_grp_s cn52xx; - struct cvmx_pip_dsa_src_grp_s cn52xxp1; - struct cvmx_pip_dsa_src_grp_s cn56xx; -}; - -union cvmx_pip_dsa_vid_grp { - uint64_t u64; - struct cvmx_pip_dsa_vid_grp_s { - uint64_t map15:4; - uint64_t map14:4; - uint64_t map13:4; - uint64_t map12:4; - uint64_t map11:4; - uint64_t map10:4; - uint64_t map9:4; - uint64_t map8:4; - uint64_t map7:4; - uint64_t map6:4; - uint64_t map5:4; - uint64_t map4:4; - uint64_t map3:4; - uint64_t map2:4; - uint64_t map1:4; - uint64_t map0:4; - } s; - struct cvmx_pip_dsa_vid_grp_s cn52xx; - struct cvmx_pip_dsa_vid_grp_s cn52xxp1; - struct cvmx_pip_dsa_vid_grp_s cn56xx; -}; - -union cvmx_pip_frm_len_chkx { - uint64_t u64; - struct cvmx_pip_frm_len_chkx_s { - uint64_t reserved_32_63:32; - uint64_t maxlen:16; - uint64_t minlen:16; - } s; - struct cvmx_pip_frm_len_chkx_s cn50xx; - struct cvmx_pip_frm_len_chkx_s cn52xx; - struct cvmx_pip_frm_len_chkx_s cn52xxp1; - struct cvmx_pip_frm_len_chkx_s cn56xx; - struct cvmx_pip_frm_len_chkx_s cn56xxp1; -}; - -union cvmx_pip_gbl_cfg { - uint64_t u64; - struct cvmx_pip_gbl_cfg_s { - uint64_t reserved_19_63:45; - uint64_t tag_syn:1; - uint64_t ip6_udp:1; - uint64_t max_l2:1; - uint64_t reserved_11_15:5; - uint64_t raw_shf:3; - uint64_t reserved_3_7:5; - uint64_t nip_shf:3; - } s; - struct cvmx_pip_gbl_cfg_s cn30xx; - struct cvmx_pip_gbl_cfg_s cn31xx; - struct cvmx_pip_gbl_cfg_s cn38xx; - struct cvmx_pip_gbl_cfg_s cn38xxp2; - struct cvmx_pip_gbl_cfg_s cn50xx; - struct cvmx_pip_gbl_cfg_s cn52xx; - struct cvmx_pip_gbl_cfg_s cn52xxp1; - struct cvmx_pip_gbl_cfg_s cn56xx; - struct cvmx_pip_gbl_cfg_s cn56xxp1; - struct cvmx_pip_gbl_cfg_s cn58xx; - struct cvmx_pip_gbl_cfg_s cn58xxp1; -}; - -union cvmx_pip_gbl_ctl { - uint64_t u64; - struct cvmx_pip_gbl_ctl_s { - uint64_t reserved_27_63:37; - uint64_t dsa_grp_tvid:1; - uint64_t dsa_grp_scmd:1; - uint64_t dsa_grp_sid:1; - uint64_t reserved_21_23:3; - uint64_t ring_en:1; - uint64_t reserved_17_19:3; - uint64_t ignrs:1; - uint64_t vs_wqe:1; - uint64_t vs_qos:1; - uint64_t l2_mal:1; - uint64_t tcp_flag:1; - uint64_t l4_len:1; - uint64_t l4_chk:1; - uint64_t l4_prt:1; - uint64_t l4_mal:1; - uint64_t reserved_6_7:2; - uint64_t ip6_eext:2; - uint64_t ip4_opts:1; - uint64_t ip_hop:1; - uint64_t ip_mal:1; - uint64_t ip_chk:1; - } s; - struct cvmx_pip_gbl_ctl_cn30xx { - uint64_t reserved_17_63:47; - uint64_t ignrs:1; - uint64_t vs_wqe:1; - uint64_t vs_qos:1; - uint64_t l2_mal:1; - uint64_t tcp_flag:1; - uint64_t l4_len:1; - uint64_t l4_chk:1; - uint64_t l4_prt:1; - uint64_t l4_mal:1; - uint64_t reserved_6_7:2; - uint64_t ip6_eext:2; - uint64_t ip4_opts:1; - uint64_t ip_hop:1; - uint64_t ip_mal:1; - uint64_t ip_chk:1; - } cn30xx; - struct cvmx_pip_gbl_ctl_cn30xx cn31xx; - struct cvmx_pip_gbl_ctl_cn30xx cn38xx; - struct cvmx_pip_gbl_ctl_cn30xx cn38xxp2; - struct cvmx_pip_gbl_ctl_cn30xx cn50xx; - struct cvmx_pip_gbl_ctl_s cn52xx; - struct cvmx_pip_gbl_ctl_s cn52xxp1; - struct cvmx_pip_gbl_ctl_s cn56xx; - struct cvmx_pip_gbl_ctl_cn56xxp1 { - uint64_t reserved_21_63:43; - uint64_t ring_en:1; - uint64_t reserved_17_19:3; - uint64_t ignrs:1; - uint64_t vs_wqe:1; - uint64_t vs_qos:1; - uint64_t l2_mal:1; - uint64_t tcp_flag:1; - uint64_t l4_len:1; - uint64_t l4_chk:1; - uint64_t l4_prt:1; - uint64_t l4_mal:1; - uint64_t reserved_6_7:2; - uint64_t ip6_eext:2; - uint64_t ip4_opts:1; - uint64_t ip_hop:1; - uint64_t ip_mal:1; - uint64_t ip_chk:1; - } cn56xxp1; - struct cvmx_pip_gbl_ctl_cn30xx cn58xx; - struct cvmx_pip_gbl_ctl_cn30xx cn58xxp1; -}; - -union cvmx_pip_hg_pri_qos { - uint64_t u64; - struct cvmx_pip_hg_pri_qos_s { - uint64_t reserved_11_63:53; - uint64_t qos:3; - uint64_t reserved_6_7:2; - uint64_t pri:6; - } s; - struct cvmx_pip_hg_pri_qos_s cn52xx; - struct cvmx_pip_hg_pri_qos_s cn52xxp1; - struct cvmx_pip_hg_pri_qos_s cn56xx; -}; - -union cvmx_pip_int_en { - uint64_t u64; - struct cvmx_pip_int_en_s { - uint64_t reserved_13_63:51; - uint64_t punyerr:1; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } s; - struct cvmx_pip_int_en_cn30xx { - uint64_t reserved_9_63:55; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } cn30xx; - struct cvmx_pip_int_en_cn30xx cn31xx; - struct cvmx_pip_int_en_cn30xx cn38xx; - struct cvmx_pip_int_en_cn30xx cn38xxp2; - struct cvmx_pip_int_en_cn50xx { - uint64_t reserved_12_63:52; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t reserved_1_1:1; - uint64_t pktdrp:1; - } cn50xx; - struct cvmx_pip_int_en_cn52xx { - uint64_t reserved_13_63:51; - uint64_t punyerr:1; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t reserved_1_1:1; - uint64_t pktdrp:1; - } cn52xx; - struct cvmx_pip_int_en_cn52xx cn52xxp1; - struct cvmx_pip_int_en_s cn56xx; - struct cvmx_pip_int_en_cn56xxp1 { - uint64_t reserved_12_63:52; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } cn56xxp1; - struct cvmx_pip_int_en_cn58xx { - uint64_t reserved_13_63:51; - uint64_t punyerr:1; - uint64_t reserved_9_11:3; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } cn58xx; - struct cvmx_pip_int_en_cn30xx cn58xxp1; -}; - -union cvmx_pip_int_reg { - uint64_t u64; - struct cvmx_pip_int_reg_s { - uint64_t reserved_13_63:51; - uint64_t punyerr:1; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } s; - struct cvmx_pip_int_reg_cn30xx { - uint64_t reserved_9_63:55; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } cn30xx; - struct cvmx_pip_int_reg_cn30xx cn31xx; - struct cvmx_pip_int_reg_cn30xx cn38xx; - struct cvmx_pip_int_reg_cn30xx cn38xxp2; - struct cvmx_pip_int_reg_cn50xx { - uint64_t reserved_12_63:52; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t reserved_1_1:1; - uint64_t pktdrp:1; - } cn50xx; - struct cvmx_pip_int_reg_cn52xx { - uint64_t reserved_13_63:51; - uint64_t punyerr:1; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t reserved_1_1:1; - uint64_t pktdrp:1; - } cn52xx; - struct cvmx_pip_int_reg_cn52xx cn52xxp1; - struct cvmx_pip_int_reg_s cn56xx; - struct cvmx_pip_int_reg_cn56xxp1 { - uint64_t reserved_12_63:52; - uint64_t lenerr:1; - uint64_t maxerr:1; - uint64_t minerr:1; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } cn56xxp1; - struct cvmx_pip_int_reg_cn58xx { - uint64_t reserved_13_63:51; - uint64_t punyerr:1; - uint64_t reserved_9_11:3; - uint64_t beperr:1; - uint64_t feperr:1; - uint64_t todoovr:1; - uint64_t skprunt:1; - uint64_t badtag:1; - uint64_t prtnxa:1; - uint64_t bckprs:1; - uint64_t crcerr:1; - uint64_t pktdrp:1; - } cn58xx; - struct cvmx_pip_int_reg_cn30xx cn58xxp1; -}; - -union cvmx_pip_ip_offset { - uint64_t u64; - struct cvmx_pip_ip_offset_s { - uint64_t reserved_3_63:61; - uint64_t offset:3; - } s; - struct cvmx_pip_ip_offset_s cn30xx; - struct cvmx_pip_ip_offset_s cn31xx; - struct cvmx_pip_ip_offset_s cn38xx; - struct cvmx_pip_ip_offset_s cn38xxp2; - struct cvmx_pip_ip_offset_s cn50xx; - struct cvmx_pip_ip_offset_s cn52xx; - struct cvmx_pip_ip_offset_s cn52xxp1; - struct cvmx_pip_ip_offset_s cn56xx; - struct cvmx_pip_ip_offset_s cn56xxp1; - struct cvmx_pip_ip_offset_s cn58xx; - struct cvmx_pip_ip_offset_s cn58xxp1; -}; - -union cvmx_pip_prt_cfgx { - uint64_t u64; - struct cvmx_pip_prt_cfgx_s { - uint64_t reserved_53_63:11; - uint64_t pad_len:1; - uint64_t vlan_len:1; - uint64_t lenerr_en:1; - uint64_t maxerr_en:1; - uint64_t minerr_en:1; - uint64_t grp_wat_47:4; - uint64_t qos_wat_47:4; - uint64_t reserved_37_39:3; - uint64_t rawdrp:1; - uint64_t tag_inc:2; - uint64_t dyn_rs:1; - uint64_t inst_hdr:1; - uint64_t grp_wat:4; - uint64_t hg_qos:1; - uint64_t qos:3; - uint64_t qos_wat:4; - uint64_t qos_vsel:1; - uint64_t qos_vod:1; - uint64_t qos_diff:1; - uint64_t qos_vlan:1; - uint64_t reserved_13_15:3; - uint64_t crc_en:1; - uint64_t higig_en:1; - uint64_t dsa_en:1; - uint64_t mode:2; - uint64_t reserved_7_7:1; - uint64_t skip:7; - } s; - struct cvmx_pip_prt_cfgx_cn30xx { - uint64_t reserved_37_63:27; - uint64_t rawdrp:1; - uint64_t tag_inc:2; - uint64_t dyn_rs:1; - uint64_t inst_hdr:1; - uint64_t grp_wat:4; - uint64_t reserved_27_27:1; - uint64_t qos:3; - uint64_t qos_wat:4; - uint64_t reserved_18_19:2; - uint64_t qos_diff:1; - uint64_t qos_vlan:1; - uint64_t reserved_10_15:6; - uint64_t mode:2; - uint64_t reserved_7_7:1; - uint64_t skip:7; - } cn30xx; - struct cvmx_pip_prt_cfgx_cn30xx cn31xx; - struct cvmx_pip_prt_cfgx_cn38xx { - uint64_t reserved_37_63:27; - uint64_t rawdrp:1; - uint64_t tag_inc:2; - uint64_t dyn_rs:1; - uint64_t inst_hdr:1; - uint64_t grp_wat:4; - uint64_t reserved_27_27:1; - uint64_t qos:3; - uint64_t qos_wat:4; - uint64_t reserved_18_19:2; - uint64_t qos_diff:1; - uint64_t qos_vlan:1; - uint64_t reserved_13_15:3; - uint64_t crc_en:1; - uint64_t reserved_10_11:2; - uint64_t mode:2; - uint64_t reserved_7_7:1; - uint64_t skip:7; - } cn38xx; - struct cvmx_pip_prt_cfgx_cn38xx cn38xxp2; - struct cvmx_pip_prt_cfgx_cn50xx { - uint64_t reserved_53_63:11; - uint64_t pad_len:1; - uint64_t vlan_len:1; - uint64_t lenerr_en:1; - uint64_t maxerr_en:1; - uint64_t minerr_en:1; - uint64_t grp_wat_47:4; - uint64_t qos_wat_47:4; - uint64_t reserved_37_39:3; - uint64_t rawdrp:1; - uint64_t tag_inc:2; - uint64_t dyn_rs:1; - uint64_t inst_hdr:1; - uint64_t grp_wat:4; - uint64_t reserved_27_27:1; - uint64_t qos:3; - uint64_t qos_wat:4; - uint64_t reserved_19_19:1; - uint64_t qos_vod:1; - uint64_t qos_diff:1; - uint64_t qos_vlan:1; - uint64_t reserved_13_15:3; - uint64_t crc_en:1; - uint64_t reserved_10_11:2; - uint64_t mode:2; - uint64_t reserved_7_7:1; - uint64_t skip:7; - } cn50xx; - struct cvmx_pip_prt_cfgx_s cn52xx; - struct cvmx_pip_prt_cfgx_s cn52xxp1; - struct cvmx_pip_prt_cfgx_s cn56xx; - struct cvmx_pip_prt_cfgx_cn50xx cn56xxp1; - struct cvmx_pip_prt_cfgx_cn58xx { - uint64_t reserved_37_63:27; - uint64_t rawdrp:1; - uint64_t tag_inc:2; - uint64_t dyn_rs:1; - uint64_t inst_hdr:1; - uint64_t grp_wat:4; - uint64_t reserved_27_27:1; - uint64_t qos:3; - uint64_t qos_wat:4; - uint64_t reserved_19_19:1; - uint64_t qos_vod:1; - uint64_t qos_diff:1; - uint64_t qos_vlan:1; - uint64_t reserved_13_15:3; - uint64_t crc_en:1; - uint64_t reserved_10_11:2; - uint64_t mode:2; - uint64_t reserved_7_7:1; - uint64_t skip:7; - } cn58xx; - struct cvmx_pip_prt_cfgx_cn58xx cn58xxp1; -}; - -union cvmx_pip_prt_tagx { - uint64_t u64; - struct cvmx_pip_prt_tagx_s { - uint64_t reserved_40_63:24; - uint64_t grptagbase:4; - uint64_t grptagmask:4; - uint64_t grptag:1; - uint64_t grptag_mskip:1; - uint64_t tag_mode:2; - uint64_t inc_vs:2; - uint64_t inc_vlan:1; - uint64_t inc_prt_flag:1; - uint64_t ip6_dprt_flag:1; - uint64_t ip4_dprt_flag:1; - uint64_t ip6_sprt_flag:1; - uint64_t ip4_sprt_flag:1; - uint64_t ip6_nxth_flag:1; - uint64_t ip4_pctl_flag:1; - uint64_t ip6_dst_flag:1; - uint64_t ip4_dst_flag:1; - uint64_t ip6_src_flag:1; - uint64_t ip4_src_flag:1; - uint64_t tcp6_tag_type:2; - uint64_t tcp4_tag_type:2; - uint64_t ip6_tag_type:2; - uint64_t ip4_tag_type:2; - uint64_t non_tag_type:2; - uint64_t grp:4; - } s; - struct cvmx_pip_prt_tagx_cn30xx { - uint64_t reserved_40_63:24; - uint64_t grptagbase:4; - uint64_t grptagmask:4; - uint64_t grptag:1; - uint64_t reserved_30_30:1; - uint64_t tag_mode:2; - uint64_t inc_vs:2; - uint64_t inc_vlan:1; - uint64_t inc_prt_flag:1; - uint64_t ip6_dprt_flag:1; - uint64_t ip4_dprt_flag:1; - uint64_t ip6_sprt_flag:1; - uint64_t ip4_sprt_flag:1; - uint64_t ip6_nxth_flag:1; - uint64_t ip4_pctl_flag:1; - uint64_t ip6_dst_flag:1; - uint64_t ip4_dst_flag:1; - uint64_t ip6_src_flag:1; - uint64_t ip4_src_flag:1; - uint64_t tcp6_tag_type:2; - uint64_t tcp4_tag_type:2; - uint64_t ip6_tag_type:2; - uint64_t ip4_tag_type:2; - uint64_t non_tag_type:2; - uint64_t grp:4; - } cn30xx; - struct cvmx_pip_prt_tagx_cn30xx cn31xx; - struct cvmx_pip_prt_tagx_cn30xx cn38xx; - struct cvmx_pip_prt_tagx_cn30xx cn38xxp2; - struct cvmx_pip_prt_tagx_s cn50xx; - struct cvmx_pip_prt_tagx_s cn52xx; - struct cvmx_pip_prt_tagx_s cn52xxp1; - struct cvmx_pip_prt_tagx_s cn56xx; - struct cvmx_pip_prt_tagx_s cn56xxp1; - struct cvmx_pip_prt_tagx_cn30xx cn58xx; - struct cvmx_pip_prt_tagx_cn30xx cn58xxp1; -}; - -union cvmx_pip_qos_diffx { - uint64_t u64; - struct cvmx_pip_qos_diffx_s { - uint64_t reserved_3_63:61; - uint64_t qos:3; - } s; - struct cvmx_pip_qos_diffx_s cn30xx; - struct cvmx_pip_qos_diffx_s cn31xx; - struct cvmx_pip_qos_diffx_s cn38xx; - struct cvmx_pip_qos_diffx_s cn38xxp2; - struct cvmx_pip_qos_diffx_s cn50xx; - struct cvmx_pip_qos_diffx_s cn52xx; - struct cvmx_pip_qos_diffx_s cn52xxp1; - struct cvmx_pip_qos_diffx_s cn56xx; - struct cvmx_pip_qos_diffx_s cn56xxp1; - struct cvmx_pip_qos_diffx_s cn58xx; - struct cvmx_pip_qos_diffx_s cn58xxp1; -}; - -union cvmx_pip_qos_vlanx { - uint64_t u64; - struct cvmx_pip_qos_vlanx_s { - uint64_t reserved_7_63:57; - uint64_t qos1:3; - uint64_t reserved_3_3:1; - uint64_t qos:3; - } s; - struct cvmx_pip_qos_vlanx_cn30xx { - uint64_t reserved_3_63:61; - uint64_t qos:3; - } cn30xx; - struct cvmx_pip_qos_vlanx_cn30xx cn31xx; - struct cvmx_pip_qos_vlanx_cn30xx cn38xx; - struct cvmx_pip_qos_vlanx_cn30xx cn38xxp2; - struct cvmx_pip_qos_vlanx_cn30xx cn50xx; - struct cvmx_pip_qos_vlanx_s cn52xx; - struct cvmx_pip_qos_vlanx_s cn52xxp1; - struct cvmx_pip_qos_vlanx_s cn56xx; - struct cvmx_pip_qos_vlanx_cn30xx cn56xxp1; - struct cvmx_pip_qos_vlanx_cn30xx cn58xx; - struct cvmx_pip_qos_vlanx_cn30xx cn58xxp1; -}; - -union cvmx_pip_qos_watchx { - uint64_t u64; - struct cvmx_pip_qos_watchx_s { - uint64_t reserved_48_63:16; - uint64_t mask:16; - uint64_t reserved_28_31:4; - uint64_t grp:4; - uint64_t reserved_23_23:1; - uint64_t qos:3; - uint64_t reserved_19_19:1; - uint64_t match_type:3; - uint64_t match_value:16; - } s; - struct cvmx_pip_qos_watchx_cn30xx { - uint64_t reserved_48_63:16; - uint64_t mask:16; - uint64_t reserved_28_31:4; - uint64_t grp:4; - uint64_t reserved_23_23:1; - uint64_t qos:3; - uint64_t reserved_18_19:2; - uint64_t match_type:2; - uint64_t match_value:16; - } cn30xx; - struct cvmx_pip_qos_watchx_cn30xx cn31xx; - struct cvmx_pip_qos_watchx_cn30xx cn38xx; - struct cvmx_pip_qos_watchx_cn30xx cn38xxp2; - struct cvmx_pip_qos_watchx_s cn50xx; - struct cvmx_pip_qos_watchx_s cn52xx; - struct cvmx_pip_qos_watchx_s cn52xxp1; - struct cvmx_pip_qos_watchx_s cn56xx; - struct cvmx_pip_qos_watchx_s cn56xxp1; - struct cvmx_pip_qos_watchx_cn30xx cn58xx; - struct cvmx_pip_qos_watchx_cn30xx cn58xxp1; -}; - -union cvmx_pip_raw_word { - uint64_t u64; - struct cvmx_pip_raw_word_s { - uint64_t reserved_56_63:8; - uint64_t word:56; - } s; - struct cvmx_pip_raw_word_s cn30xx; - struct cvmx_pip_raw_word_s cn31xx; - struct cvmx_pip_raw_word_s cn38xx; - struct cvmx_pip_raw_word_s cn38xxp2; - struct cvmx_pip_raw_word_s cn50xx; - struct cvmx_pip_raw_word_s cn52xx; - struct cvmx_pip_raw_word_s cn52xxp1; - struct cvmx_pip_raw_word_s cn56xx; - struct cvmx_pip_raw_word_s cn56xxp1; - struct cvmx_pip_raw_word_s cn58xx; - struct cvmx_pip_raw_word_s cn58xxp1; -}; - -union cvmx_pip_sft_rst { - uint64_t u64; - struct cvmx_pip_sft_rst_s { - uint64_t reserved_1_63:63; - uint64_t rst:1; - } s; - struct cvmx_pip_sft_rst_s cn30xx; - struct cvmx_pip_sft_rst_s cn31xx; - struct cvmx_pip_sft_rst_s cn38xx; - struct cvmx_pip_sft_rst_s cn50xx; - struct cvmx_pip_sft_rst_s cn52xx; - struct cvmx_pip_sft_rst_s cn52xxp1; - struct cvmx_pip_sft_rst_s cn56xx; - struct cvmx_pip_sft_rst_s cn56xxp1; - struct cvmx_pip_sft_rst_s cn58xx; - struct cvmx_pip_sft_rst_s cn58xxp1; -}; - -union cvmx_pip_stat0_prtx { - uint64_t u64; - struct cvmx_pip_stat0_prtx_s { - uint64_t drp_pkts:32; - uint64_t drp_octs:32; - } s; - struct cvmx_pip_stat0_prtx_s cn30xx; - struct cvmx_pip_stat0_prtx_s cn31xx; - struct cvmx_pip_stat0_prtx_s cn38xx; - struct cvmx_pip_stat0_prtx_s cn38xxp2; - struct cvmx_pip_stat0_prtx_s cn50xx; - struct cvmx_pip_stat0_prtx_s cn52xx; - struct cvmx_pip_stat0_prtx_s cn52xxp1; - struct cvmx_pip_stat0_prtx_s cn56xx; - struct cvmx_pip_stat0_prtx_s cn56xxp1; - struct cvmx_pip_stat0_prtx_s cn58xx; - struct cvmx_pip_stat0_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat1_prtx { - uint64_t u64; - struct cvmx_pip_stat1_prtx_s { - uint64_t reserved_48_63:16; - uint64_t octs:48; - } s; - struct cvmx_pip_stat1_prtx_s cn30xx; - struct cvmx_pip_stat1_prtx_s cn31xx; - struct cvmx_pip_stat1_prtx_s cn38xx; - struct cvmx_pip_stat1_prtx_s cn38xxp2; - struct cvmx_pip_stat1_prtx_s cn50xx; - struct cvmx_pip_stat1_prtx_s cn52xx; - struct cvmx_pip_stat1_prtx_s cn52xxp1; - struct cvmx_pip_stat1_prtx_s cn56xx; - struct cvmx_pip_stat1_prtx_s cn56xxp1; - struct cvmx_pip_stat1_prtx_s cn58xx; - struct cvmx_pip_stat1_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat2_prtx { - uint64_t u64; - struct cvmx_pip_stat2_prtx_s { - uint64_t pkts:32; - uint64_t raw:32; - } s; - struct cvmx_pip_stat2_prtx_s cn30xx; - struct cvmx_pip_stat2_prtx_s cn31xx; - struct cvmx_pip_stat2_prtx_s cn38xx; - struct cvmx_pip_stat2_prtx_s cn38xxp2; - struct cvmx_pip_stat2_prtx_s cn50xx; - struct cvmx_pip_stat2_prtx_s cn52xx; - struct cvmx_pip_stat2_prtx_s cn52xxp1; - struct cvmx_pip_stat2_prtx_s cn56xx; - struct cvmx_pip_stat2_prtx_s cn56xxp1; - struct cvmx_pip_stat2_prtx_s cn58xx; - struct cvmx_pip_stat2_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat3_prtx { - uint64_t u64; - struct cvmx_pip_stat3_prtx_s { - uint64_t bcst:32; - uint64_t mcst:32; - } s; - struct cvmx_pip_stat3_prtx_s cn30xx; - struct cvmx_pip_stat3_prtx_s cn31xx; - struct cvmx_pip_stat3_prtx_s cn38xx; - struct cvmx_pip_stat3_prtx_s cn38xxp2; - struct cvmx_pip_stat3_prtx_s cn50xx; - struct cvmx_pip_stat3_prtx_s cn52xx; - struct cvmx_pip_stat3_prtx_s cn52xxp1; - struct cvmx_pip_stat3_prtx_s cn56xx; - struct cvmx_pip_stat3_prtx_s cn56xxp1; - struct cvmx_pip_stat3_prtx_s cn58xx; - struct cvmx_pip_stat3_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat4_prtx { - uint64_t u64; - struct cvmx_pip_stat4_prtx_s { - uint64_t h65to127:32; - uint64_t h64:32; - } s; - struct cvmx_pip_stat4_prtx_s cn30xx; - struct cvmx_pip_stat4_prtx_s cn31xx; - struct cvmx_pip_stat4_prtx_s cn38xx; - struct cvmx_pip_stat4_prtx_s cn38xxp2; - struct cvmx_pip_stat4_prtx_s cn50xx; - struct cvmx_pip_stat4_prtx_s cn52xx; - struct cvmx_pip_stat4_prtx_s cn52xxp1; - struct cvmx_pip_stat4_prtx_s cn56xx; - struct cvmx_pip_stat4_prtx_s cn56xxp1; - struct cvmx_pip_stat4_prtx_s cn58xx; - struct cvmx_pip_stat4_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat5_prtx { - uint64_t u64; - struct cvmx_pip_stat5_prtx_s { - uint64_t h256to511:32; - uint64_t h128to255:32; - } s; - struct cvmx_pip_stat5_prtx_s cn30xx; - struct cvmx_pip_stat5_prtx_s cn31xx; - struct cvmx_pip_stat5_prtx_s cn38xx; - struct cvmx_pip_stat5_prtx_s cn38xxp2; - struct cvmx_pip_stat5_prtx_s cn50xx; - struct cvmx_pip_stat5_prtx_s cn52xx; - struct cvmx_pip_stat5_prtx_s cn52xxp1; - struct cvmx_pip_stat5_prtx_s cn56xx; - struct cvmx_pip_stat5_prtx_s cn56xxp1; - struct cvmx_pip_stat5_prtx_s cn58xx; - struct cvmx_pip_stat5_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat6_prtx { - uint64_t u64; - struct cvmx_pip_stat6_prtx_s { - uint64_t h1024to1518:32; - uint64_t h512to1023:32; - } s; - struct cvmx_pip_stat6_prtx_s cn30xx; - struct cvmx_pip_stat6_prtx_s cn31xx; - struct cvmx_pip_stat6_prtx_s cn38xx; - struct cvmx_pip_stat6_prtx_s cn38xxp2; - struct cvmx_pip_stat6_prtx_s cn50xx; - struct cvmx_pip_stat6_prtx_s cn52xx; - struct cvmx_pip_stat6_prtx_s cn52xxp1; - struct cvmx_pip_stat6_prtx_s cn56xx; - struct cvmx_pip_stat6_prtx_s cn56xxp1; - struct cvmx_pip_stat6_prtx_s cn58xx; - struct cvmx_pip_stat6_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat7_prtx { - uint64_t u64; - struct cvmx_pip_stat7_prtx_s { - uint64_t fcs:32; - uint64_t h1519:32; - } s; - struct cvmx_pip_stat7_prtx_s cn30xx; - struct cvmx_pip_stat7_prtx_s cn31xx; - struct cvmx_pip_stat7_prtx_s cn38xx; - struct cvmx_pip_stat7_prtx_s cn38xxp2; - struct cvmx_pip_stat7_prtx_s cn50xx; - struct cvmx_pip_stat7_prtx_s cn52xx; - struct cvmx_pip_stat7_prtx_s cn52xxp1; - struct cvmx_pip_stat7_prtx_s cn56xx; - struct cvmx_pip_stat7_prtx_s cn56xxp1; - struct cvmx_pip_stat7_prtx_s cn58xx; - struct cvmx_pip_stat7_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat8_prtx { - uint64_t u64; - struct cvmx_pip_stat8_prtx_s { - uint64_t frag:32; - uint64_t undersz:32; - } s; - struct cvmx_pip_stat8_prtx_s cn30xx; - struct cvmx_pip_stat8_prtx_s cn31xx; - struct cvmx_pip_stat8_prtx_s cn38xx; - struct cvmx_pip_stat8_prtx_s cn38xxp2; - struct cvmx_pip_stat8_prtx_s cn50xx; - struct cvmx_pip_stat8_prtx_s cn52xx; - struct cvmx_pip_stat8_prtx_s cn52xxp1; - struct cvmx_pip_stat8_prtx_s cn56xx; - struct cvmx_pip_stat8_prtx_s cn56xxp1; - struct cvmx_pip_stat8_prtx_s cn58xx; - struct cvmx_pip_stat8_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat9_prtx { - uint64_t u64; - struct cvmx_pip_stat9_prtx_s { - uint64_t jabber:32; - uint64_t oversz:32; - } s; - struct cvmx_pip_stat9_prtx_s cn30xx; - struct cvmx_pip_stat9_prtx_s cn31xx; - struct cvmx_pip_stat9_prtx_s cn38xx; - struct cvmx_pip_stat9_prtx_s cn38xxp2; - struct cvmx_pip_stat9_prtx_s cn50xx; - struct cvmx_pip_stat9_prtx_s cn52xx; - struct cvmx_pip_stat9_prtx_s cn52xxp1; - struct cvmx_pip_stat9_prtx_s cn56xx; - struct cvmx_pip_stat9_prtx_s cn56xxp1; - struct cvmx_pip_stat9_prtx_s cn58xx; - struct cvmx_pip_stat9_prtx_s cn58xxp1; -}; - -union cvmx_pip_stat_ctl { - uint64_t u64; - struct cvmx_pip_stat_ctl_s { - uint64_t reserved_1_63:63; - uint64_t rdclr:1; - } s; - struct cvmx_pip_stat_ctl_s cn30xx; - struct cvmx_pip_stat_ctl_s cn31xx; - struct cvmx_pip_stat_ctl_s cn38xx; - struct cvmx_pip_stat_ctl_s cn38xxp2; - struct cvmx_pip_stat_ctl_s cn50xx; - struct cvmx_pip_stat_ctl_s cn52xx; - struct cvmx_pip_stat_ctl_s cn52xxp1; - struct cvmx_pip_stat_ctl_s cn56xx; - struct cvmx_pip_stat_ctl_s cn56xxp1; - struct cvmx_pip_stat_ctl_s cn58xx; - struct cvmx_pip_stat_ctl_s cn58xxp1; -}; - -union cvmx_pip_stat_inb_errsx { - uint64_t u64; - struct cvmx_pip_stat_inb_errsx_s { - uint64_t reserved_16_63:48; - uint64_t errs:16; - } s; - struct cvmx_pip_stat_inb_errsx_s cn30xx; - struct cvmx_pip_stat_inb_errsx_s cn31xx; - struct cvmx_pip_stat_inb_errsx_s cn38xx; - struct cvmx_pip_stat_inb_errsx_s cn38xxp2; - struct cvmx_pip_stat_inb_errsx_s cn50xx; - struct cvmx_pip_stat_inb_errsx_s cn52xx; - struct cvmx_pip_stat_inb_errsx_s cn52xxp1; - struct cvmx_pip_stat_inb_errsx_s cn56xx; - struct cvmx_pip_stat_inb_errsx_s cn56xxp1; - struct cvmx_pip_stat_inb_errsx_s cn58xx; - struct cvmx_pip_stat_inb_errsx_s cn58xxp1; -}; - -union cvmx_pip_stat_inb_octsx { - uint64_t u64; - struct cvmx_pip_stat_inb_octsx_s { - uint64_t reserved_48_63:16; - uint64_t octs:48; - } s; - struct cvmx_pip_stat_inb_octsx_s cn30xx; - struct cvmx_pip_stat_inb_octsx_s cn31xx; - struct cvmx_pip_stat_inb_octsx_s cn38xx; - struct cvmx_pip_stat_inb_octsx_s cn38xxp2; - struct cvmx_pip_stat_inb_octsx_s cn50xx; - struct cvmx_pip_stat_inb_octsx_s cn52xx; - struct cvmx_pip_stat_inb_octsx_s cn52xxp1; - struct cvmx_pip_stat_inb_octsx_s cn56xx; - struct cvmx_pip_stat_inb_octsx_s cn56xxp1; - struct cvmx_pip_stat_inb_octsx_s cn58xx; - struct cvmx_pip_stat_inb_octsx_s cn58xxp1; -}; - -union cvmx_pip_stat_inb_pktsx { - uint64_t u64; - struct cvmx_pip_stat_inb_pktsx_s { - uint64_t reserved_32_63:32; - uint64_t pkts:32; - } s; - struct cvmx_pip_stat_inb_pktsx_s cn30xx; - struct cvmx_pip_stat_inb_pktsx_s cn31xx; - struct cvmx_pip_stat_inb_pktsx_s cn38xx; - struct cvmx_pip_stat_inb_pktsx_s cn38xxp2; - struct cvmx_pip_stat_inb_pktsx_s cn50xx; - struct cvmx_pip_stat_inb_pktsx_s cn52xx; - struct cvmx_pip_stat_inb_pktsx_s cn52xxp1; - struct cvmx_pip_stat_inb_pktsx_s cn56xx; - struct cvmx_pip_stat_inb_pktsx_s cn56xxp1; - struct cvmx_pip_stat_inb_pktsx_s cn58xx; - struct cvmx_pip_stat_inb_pktsx_s cn58xxp1; -}; - -union cvmx_pip_tag_incx { - uint64_t u64; - struct cvmx_pip_tag_incx_s { - uint64_t reserved_8_63:56; - uint64_t en:8; - } s; - struct cvmx_pip_tag_incx_s cn30xx; - struct cvmx_pip_tag_incx_s cn31xx; - struct cvmx_pip_tag_incx_s cn38xx; - struct cvmx_pip_tag_incx_s cn38xxp2; - struct cvmx_pip_tag_incx_s cn50xx; - struct cvmx_pip_tag_incx_s cn52xx; - struct cvmx_pip_tag_incx_s cn52xxp1; - struct cvmx_pip_tag_incx_s cn56xx; - struct cvmx_pip_tag_incx_s cn56xxp1; - struct cvmx_pip_tag_incx_s cn58xx; - struct cvmx_pip_tag_incx_s cn58xxp1; -}; - -union cvmx_pip_tag_mask { - uint64_t u64; - struct cvmx_pip_tag_mask_s { - uint64_t reserved_16_63:48; - uint64_t mask:16; - } s; - struct cvmx_pip_tag_mask_s cn30xx; - struct cvmx_pip_tag_mask_s cn31xx; - struct cvmx_pip_tag_mask_s cn38xx; - struct cvmx_pip_tag_mask_s cn38xxp2; - struct cvmx_pip_tag_mask_s cn50xx; - struct cvmx_pip_tag_mask_s cn52xx; - struct cvmx_pip_tag_mask_s cn52xxp1; - struct cvmx_pip_tag_mask_s cn56xx; - struct cvmx_pip_tag_mask_s cn56xxp1; - struct cvmx_pip_tag_mask_s cn58xx; - struct cvmx_pip_tag_mask_s cn58xxp1; -}; - -union cvmx_pip_tag_secret { - uint64_t u64; - struct cvmx_pip_tag_secret_s { - uint64_t reserved_32_63:32; - uint64_t dst:16; - uint64_t src:16; - } s; - struct cvmx_pip_tag_secret_s cn30xx; - struct cvmx_pip_tag_secret_s cn31xx; - struct cvmx_pip_tag_secret_s cn38xx; - struct cvmx_pip_tag_secret_s cn38xxp2; - struct cvmx_pip_tag_secret_s cn50xx; - struct cvmx_pip_tag_secret_s cn52xx; - struct cvmx_pip_tag_secret_s cn52xxp1; - struct cvmx_pip_tag_secret_s cn56xx; - struct cvmx_pip_tag_secret_s cn56xxp1; - struct cvmx_pip_tag_secret_s cn58xx; - struct cvmx_pip_tag_secret_s cn58xxp1; -}; - -union cvmx_pip_todo_entry { - uint64_t u64; - struct cvmx_pip_todo_entry_s { - uint64_t val:1; - uint64_t reserved_62_62:1; - uint64_t entry:62; - } s; - struct cvmx_pip_todo_entry_s cn30xx; - struct cvmx_pip_todo_entry_s cn31xx; - struct cvmx_pip_todo_entry_s cn38xx; - struct cvmx_pip_todo_entry_s cn38xxp2; - struct cvmx_pip_todo_entry_s cn50xx; - struct cvmx_pip_todo_entry_s cn52xx; - struct cvmx_pip_todo_entry_s cn52xxp1; - struct cvmx_pip_todo_entry_s cn56xx; - struct cvmx_pip_todo_entry_s cn56xxp1; - struct cvmx_pip_todo_entry_s cn58xx; - struct cvmx_pip_todo_entry_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-pip.h b/drivers/staging/octeon/cvmx-pip.h deleted file mode 100644 index 78dbce8f2c5e..000000000000 --- a/drivers/staging/octeon/cvmx-pip.h +++ /dev/null @@ -1,524 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Interface to the hardware Packet Input Processing unit. - * - */ - -#ifndef __CVMX_PIP_H__ -#define __CVMX_PIP_H__ - -#include "cvmx-wqe.h" -#include "cvmx-fpa.h" -#include "cvmx-pip-defs.h" - -#define CVMX_PIP_NUM_INPUT_PORTS 40 -#define CVMX_PIP_NUM_WATCHERS 4 - -/* - * Encodes the different error and exception codes - */ -typedef enum { - CVMX_PIP_L4_NO_ERR = 0ull, - /* - * 1 = TCP (UDP) packet not long enough to cover TCP (UDP) - * header - */ - CVMX_PIP_L4_MAL_ERR = 1ull, - /* 2 = TCP/UDP checksum failure */ - CVMX_PIP_CHK_ERR = 2ull, - /* - * 3 = TCP/UDP length check (TCP/UDP length does not match IP - * length). - */ - CVMX_PIP_L4_LENGTH_ERR = 3ull, - /* 4 = illegal TCP/UDP port (either source or dest port is zero) */ - CVMX_PIP_BAD_PRT_ERR = 4ull, - /* 8 = TCP flags = FIN only */ - CVMX_PIP_TCP_FLG8_ERR = 8ull, - /* 9 = TCP flags = 0 */ - CVMX_PIP_TCP_FLG9_ERR = 9ull, - /* 10 = TCP flags = FIN+RST+* */ - CVMX_PIP_TCP_FLG10_ERR = 10ull, - /* 11 = TCP flags = SYN+URG+* */ - CVMX_PIP_TCP_FLG11_ERR = 11ull, - /* 12 = TCP flags = SYN+RST+* */ - CVMX_PIP_TCP_FLG12_ERR = 12ull, - /* 13 = TCP flags = SYN+FIN+* */ - CVMX_PIP_TCP_FLG13_ERR = 13ull -} cvmx_pip_l4_err_t; - -typedef enum { - - CVMX_PIP_IP_NO_ERR = 0ull, - /* 1 = not IPv4 or IPv6 */ - CVMX_PIP_NOT_IP = 1ull, - /* 2 = IPv4 header checksum violation */ - CVMX_PIP_IPV4_HDR_CHK = 2ull, - /* 3 = malformed (packet not long enough to cover IP hdr) */ - CVMX_PIP_IP_MAL_HDR = 3ull, - /* 4 = malformed (packet not long enough to cover len in IP hdr) */ - CVMX_PIP_IP_MAL_PKT = 4ull, - /* 5 = TTL / hop count equal zero */ - CVMX_PIP_TTL_HOP = 5ull, - /* 6 = IPv4 options / IPv6 early extension headers */ - CVMX_PIP_OPTS = 6ull -} cvmx_pip_ip_exc_t; - -/** - * NOTES - * late collision (data received before collision) - * late collisions cannot be detected by the receiver - * they would appear as JAM bits which would appear as bad FCS - * or carrier extend error which is CVMX_PIP_EXTEND_ERR - */ -typedef enum { - /* No error */ - CVMX_PIP_RX_NO_ERR = 0ull, - /* RGM+SPI 1 = partially received packet (buffering/bandwidth - * not adequate) */ - CVMX_PIP_PARTIAL_ERR = 1ull, - /* RGM+SPI 2 = receive packet too large and truncated */ - CVMX_PIP_JABBER_ERR = 2ull, - /* - * RGM 3 = max frame error (pkt len > max frame len) (with FCS - * error) - */ - CVMX_PIP_OVER_FCS_ERR = 3ull, - /* RGM+SPI 4 = max frame error (pkt len > max frame len) */ - CVMX_PIP_OVER_ERR = 4ull, - /* - * RGM 5 = nibble error (data not byte multiple - 100M and 10M - * only) - */ - CVMX_PIP_ALIGN_ERR = 5ull, - /* - * RGM 6 = min frame error (pkt len < min frame len) (with FCS - * error) - */ - CVMX_PIP_UNDER_FCS_ERR = 6ull, - /* RGM 7 = FCS error */ - CVMX_PIP_GMX_FCS_ERR = 7ull, - /* RGM+SPI 8 = min frame error (pkt len < min frame len) */ - CVMX_PIP_UNDER_ERR = 8ull, - /* RGM 9 = Frame carrier extend error */ - CVMX_PIP_EXTEND_ERR = 9ull, - /* - * RGM 10 = length mismatch (len did not match len in L2 - * length/type) - */ - CVMX_PIP_LENGTH_ERR = 10ull, - /* RGM 11 = Frame error (some or all data bits marked err) */ - CVMX_PIP_DAT_ERR = 11ull, - /* SPI 11 = DIP4 error */ - CVMX_PIP_DIP_ERR = 11ull, - /* - * RGM 12 = packet was not large enough to pass the skipper - - * no inspection could occur. - */ - CVMX_PIP_SKIP_ERR = 12ull, - /* - * RGM 13 = studder error (data not repeated - 100M and 10M - * only) - */ - CVMX_PIP_NIBBLE_ERR = 13ull, - /* RGM+SPI 16 = FCS error */ - CVMX_PIP_PIP_FCS = 16L, - /* - * RGM+SPI+PCI 17 = packet was not large enough to pass the - * skipper - no inspection could occur. - */ - CVMX_PIP_PIP_SKIP_ERR = 17L, - /* - * RGM+SPI+PCI 18 = malformed l2 (packet not long enough to - * cover L2 hdr). - */ - CVMX_PIP_PIP_L2_MAL_HDR = 18L - /* - * NOTES: xx = late collision (data received before collision) - * late collisions cannot be detected by the receiver - * they would appear as JAM bits which would appear as - * bad FCS or carrier extend error which is - * CVMX_PIP_EXTEND_ERR - */ -} cvmx_pip_rcv_err_t; - -/** - * This defines the err_code field errors in the work Q entry - */ -typedef union { - cvmx_pip_l4_err_t l4_err; - cvmx_pip_ip_exc_t ip_exc; - cvmx_pip_rcv_err_t rcv_err; -} cvmx_pip_err_t; - -/** - * Status statistics for a port - */ -typedef struct { - /* Inbound octets marked to be dropped by the IPD */ - uint32_t dropped_octets; - /* Inbound packets marked to be dropped by the IPD */ - uint32_t dropped_packets; - /* RAW PCI Packets received by PIP per port */ - uint32_t pci_raw_packets; - /* Number of octets processed by PIP */ - uint32_t octets; - /* Number of packets processed by PIP */ - uint32_t packets; - /* - * Number of indentified L2 multicast packets. Does not - * include broadcast packets. Only includes packets whose - * parse mode is SKIP_TO_L2 - */ - uint32_t multicast_packets; - /* - * Number of indentified L2 broadcast packets. Does not - * include multicast packets. Only includes packets whose - * parse mode is SKIP_TO_L2 - */ - uint32_t broadcast_packets; - /* Number of 64B packets */ - uint32_t len_64_packets; - /* Number of 65-127B packets */ - uint32_t len_65_127_packets; - /* Number of 128-255B packets */ - uint32_t len_128_255_packets; - /* Number of 256-511B packets */ - uint32_t len_256_511_packets; - /* Number of 512-1023B packets */ - uint32_t len_512_1023_packets; - /* Number of 1024-1518B packets */ - uint32_t len_1024_1518_packets; - /* Number of 1519-max packets */ - uint32_t len_1519_max_packets; - /* Number of packets with FCS or Align opcode errors */ - uint32_t fcs_align_err_packets; - /* Number of packets with length < min */ - uint32_t runt_packets; - /* Number of packets with length < min and FCS error */ - uint32_t runt_crc_packets; - /* Number of packets with length > max */ - uint32_t oversize_packets; - /* Number of packets with length > max and FCS error */ - uint32_t oversize_crc_packets; - /* Number of packets without GMX/SPX/PCI errors received by PIP */ - uint32_t inb_packets; - /* - * Total number of octets from all packets received by PIP, - * including CRC - */ - uint64_t inb_octets; - /* Number of packets with GMX/SPX/PCI errors received by PIP */ - uint16_t inb_errors; -} cvmx_pip_port_status_t; - -/** - * Definition of the PIP custom header that can be prepended - * to a packet by external hardware. - */ -typedef union { - uint64_t u64; - struct { - /* - * Documented as R - Set if the Packet is RAWFULL. If - * set, this header must be the full 8 bytes. - */ - uint64_t rawfull:1; - /* Must be zero */ - uint64_t reserved0:5; - /* PIP parse mode for this packet */ - uint64_t parse_mode:2; - /* Must be zero */ - uint64_t reserved1:1; - /* - * Skip amount, including this header, to the - * beginning of the packet - */ - uint64_t skip_len:7; - /* Must be zero */ - uint64_t reserved2:6; - /* POW input queue for this packet */ - uint64_t qos:3; - /* POW input group for this packet */ - uint64_t grp:4; - /* - * Flag to store this packet in the work queue entry, - * if possible - */ - uint64_t rs:1; - /* POW input tag type */ - uint64_t tag_type:2; - /* POW input tag */ - uint64_t tag:32; - } s; -} cvmx_pip_pkt_inst_hdr_t; - -/* CSR typedefs have been moved to cvmx-csr-*.h */ - -/** - * Configure an ethernet input port - * - * @port_num: Port number to configure - * @port_cfg: Port hardware configuration - * @port_tag_cfg: - * Port POW tagging configuration - */ -static inline void cvmx_pip_config_port(uint64_t port_num, - union cvmx_pip_prt_cfgx port_cfg, - union cvmx_pip_prt_tagx port_tag_cfg) -{ - cvmx_write_csr(CVMX_PIP_PRT_CFGX(port_num), port_cfg.u64); - cvmx_write_csr(CVMX_PIP_PRT_TAGX(port_num), port_tag_cfg.u64); -} -#if 0 -/** - * @deprecated This function is a thin wrapper around the Pass1 version - * of the CVMX_PIP_QOS_WATCHX CSR; Pass2 has added a field for - * setting the group that is incompatible with this function, - * the preferred upgrade path is to use the CSR directly. - * - * Configure the global QoS packet watchers. Each watcher is - * capable of matching a field in a packet to determine the - * QoS queue for scheduling. - * - * @watcher: Watcher number to configure (0 - 3). - * @match_type: Watcher match type - * @match_value: - * Value the watcher will match against - * @qos: QoS queue for packets matching this watcher - */ -static inline void cvmx_pip_config_watcher(uint64_t watcher, - cvmx_pip_qos_watch_types match_type, - uint64_t match_value, uint64_t qos) -{ - cvmx_pip_port_watcher_cfg_t watcher_config; - - watcher_config.u64 = 0; - watcher_config.s.match_type = match_type; - watcher_config.s.match_value = match_value; - watcher_config.s.qos = qos; - - cvmx_write_csr(CVMX_PIP_QOS_WATCHX(watcher), watcher_config.u64); -} -#endif -/** - * Configure the VLAN priority to QoS queue mapping. - * - * @vlan_priority: - * VLAN priority (0-7) - * @qos: QoS queue for packets matching this watcher - */ -static inline void cvmx_pip_config_vlan_qos(uint64_t vlan_priority, - uint64_t qos) -{ - union cvmx_pip_qos_vlanx pip_qos_vlanx; - pip_qos_vlanx.u64 = 0; - pip_qos_vlanx.s.qos = qos; - cvmx_write_csr(CVMX_PIP_QOS_VLANX(vlan_priority), pip_qos_vlanx.u64); -} - -/** - * Configure the Diffserv to QoS queue mapping. - * - * @diffserv: Diffserv field value (0-63) - * @qos: QoS queue for packets matching this watcher - */ -static inline void cvmx_pip_config_diffserv_qos(uint64_t diffserv, uint64_t qos) -{ - union cvmx_pip_qos_diffx pip_qos_diffx; - pip_qos_diffx.u64 = 0; - pip_qos_diffx.s.qos = qos; - cvmx_write_csr(CVMX_PIP_QOS_DIFFX(diffserv), pip_qos_diffx.u64); -} - -/** - * Get the status counters for a port. - * - * @port_num: Port number to get statistics for. - * @clear: Set to 1 to clear the counters after they are read - * @status: Where to put the results. - */ -static inline void cvmx_pip_get_port_status(uint64_t port_num, uint64_t clear, - cvmx_pip_port_status_t *status) -{ - union cvmx_pip_stat_ctl pip_stat_ctl; - union cvmx_pip_stat0_prtx stat0; - union cvmx_pip_stat1_prtx stat1; - union cvmx_pip_stat2_prtx stat2; - union cvmx_pip_stat3_prtx stat3; - union cvmx_pip_stat4_prtx stat4; - union cvmx_pip_stat5_prtx stat5; - union cvmx_pip_stat6_prtx stat6; - union cvmx_pip_stat7_prtx stat7; - union cvmx_pip_stat8_prtx stat8; - union cvmx_pip_stat9_prtx stat9; - union cvmx_pip_stat_inb_pktsx pip_stat_inb_pktsx; - union cvmx_pip_stat_inb_octsx pip_stat_inb_octsx; - union cvmx_pip_stat_inb_errsx pip_stat_inb_errsx; - - pip_stat_ctl.u64 = 0; - pip_stat_ctl.s.rdclr = clear; - cvmx_write_csr(CVMX_PIP_STAT_CTL, pip_stat_ctl.u64); - - stat0.u64 = cvmx_read_csr(CVMX_PIP_STAT0_PRTX(port_num)); - stat1.u64 = cvmx_read_csr(CVMX_PIP_STAT1_PRTX(port_num)); - stat2.u64 = cvmx_read_csr(CVMX_PIP_STAT2_PRTX(port_num)); - stat3.u64 = cvmx_read_csr(CVMX_PIP_STAT3_PRTX(port_num)); - stat4.u64 = cvmx_read_csr(CVMX_PIP_STAT4_PRTX(port_num)); - stat5.u64 = cvmx_read_csr(CVMX_PIP_STAT5_PRTX(port_num)); - stat6.u64 = cvmx_read_csr(CVMX_PIP_STAT6_PRTX(port_num)); - stat7.u64 = cvmx_read_csr(CVMX_PIP_STAT7_PRTX(port_num)); - stat8.u64 = cvmx_read_csr(CVMX_PIP_STAT8_PRTX(port_num)); - stat9.u64 = cvmx_read_csr(CVMX_PIP_STAT9_PRTX(port_num)); - pip_stat_inb_pktsx.u64 = - cvmx_read_csr(CVMX_PIP_STAT_INB_PKTSX(port_num)); - pip_stat_inb_octsx.u64 = - cvmx_read_csr(CVMX_PIP_STAT_INB_OCTSX(port_num)); - pip_stat_inb_errsx.u64 = - cvmx_read_csr(CVMX_PIP_STAT_INB_ERRSX(port_num)); - - status->dropped_octets = stat0.s.drp_octs; - status->dropped_packets = stat0.s.drp_pkts; - status->octets = stat1.s.octs; - status->pci_raw_packets = stat2.s.raw; - status->packets = stat2.s.pkts; - status->multicast_packets = stat3.s.mcst; - status->broadcast_packets = stat3.s.bcst; - status->len_64_packets = stat4.s.h64; - status->len_65_127_packets = stat4.s.h65to127; - status->len_128_255_packets = stat5.s.h128to255; - status->len_256_511_packets = stat5.s.h256to511; - status->len_512_1023_packets = stat6.s.h512to1023; - status->len_1024_1518_packets = stat6.s.h1024to1518; - status->len_1519_max_packets = stat7.s.h1519; - status->fcs_align_err_packets = stat7.s.fcs; - status->runt_packets = stat8.s.undersz; - status->runt_crc_packets = stat8.s.frag; - status->oversize_packets = stat9.s.oversz; - status->oversize_crc_packets = stat9.s.jabber; - status->inb_packets = pip_stat_inb_pktsx.s.pkts; - status->inb_octets = pip_stat_inb_octsx.s.octs; - status->inb_errors = pip_stat_inb_errsx.s.errs; - - if (cvmx_octeon_is_pass1()) { - /* - * Kludge to fix Octeon Pass 1 errata - Drop counts - * don't work. - */ - if (status->inb_packets > status->packets) - status->dropped_packets = - status->inb_packets - status->packets; - else - status->dropped_packets = 0; - if (status->inb_octets - status->inb_packets * 4 > - status->octets) - status->dropped_octets = - status->inb_octets - status->inb_packets * 4 - - status->octets; - else - status->dropped_octets = 0; - } -} - -/** - * Configure the hardware CRC engine - * - * @interface: Interface to configure (0 or 1) - * @invert_result: - * Invert the result of the CRC - * @reflect: Reflect - * @initialization_vector: - * CRC initialization vector - */ -static inline void cvmx_pip_config_crc(uint64_t interface, - uint64_t invert_result, uint64_t reflect, - uint32_t initialization_vector) -{ - if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) { - union cvmx_pip_crc_ctlx config; - union cvmx_pip_crc_ivx pip_crc_ivx; - - config.u64 = 0; - config.s.invres = invert_result; - config.s.reflect = reflect; - cvmx_write_csr(CVMX_PIP_CRC_CTLX(interface), config.u64); - - pip_crc_ivx.u64 = 0; - pip_crc_ivx.s.iv = initialization_vector; - cvmx_write_csr(CVMX_PIP_CRC_IVX(interface), pip_crc_ivx.u64); - } -} - -/** - * Clear all bits in a tag mask. This should be called on - * startup before any calls to cvmx_pip_tag_mask_set. Each bit - * set in the final mask represent a byte used in the packet for - * tag generation. - * - * @mask_index: Which tag mask to clear (0..3) - */ -static inline void cvmx_pip_tag_mask_clear(uint64_t mask_index) -{ - uint64_t index; - union cvmx_pip_tag_incx pip_tag_incx; - pip_tag_incx.u64 = 0; - pip_tag_incx.s.en = 0; - for (index = mask_index * 16; index < (mask_index + 1) * 16; index++) - cvmx_write_csr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); -} - -/** - * Sets a range of bits in the tag mask. The tag mask is used - * when the cvmx_pip_port_tag_cfg_t tag_mode is non zero. - * There are four separate masks that can be configured. - * - * @mask_index: Which tag mask to modify (0..3) - * @offset: Offset into the bitmask to set bits at. Use the GCC macro - * offsetof() to determine the offsets into packet headers. - * For example, offsetof(ethhdr, protocol) returns the offset - * of the ethernet protocol field. The bitmask selects which - * bytes to include the the tag, with bit offset X selecting - * byte at offset X from the beginning of the packet data. - * @len: Number of bytes to include. Usually this is the sizeof() - * the field. - */ -static inline void cvmx_pip_tag_mask_set(uint64_t mask_index, uint64_t offset, - uint64_t len) -{ - while (len--) { - union cvmx_pip_tag_incx pip_tag_incx; - uint64_t index = mask_index * 16 + offset / 8; - pip_tag_incx.u64 = cvmx_read_csr(CVMX_PIP_TAG_INCX(index)); - pip_tag_incx.s.en |= 0x80 >> (offset & 0x7); - cvmx_write_csr(CVMX_PIP_TAG_INCX(index), pip_tag_incx.u64); - offset++; - } -} - -#endif /* __CVMX_PIP_H__ */ diff --git a/drivers/staging/octeon/cvmx-pko-defs.h b/drivers/staging/octeon/cvmx-pko-defs.h deleted file mode 100644 index 50e779cf1ad8..000000000000 --- a/drivers/staging/octeon/cvmx-pko-defs.h +++ /dev/null @@ -1,1133 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_PKO_DEFS_H__ -#define __CVMX_PKO_DEFS_H__ - -#define CVMX_PKO_MEM_COUNT0 \ - CVMX_ADD_IO_SEG(0x0001180050001080ull) -#define CVMX_PKO_MEM_COUNT1 \ - CVMX_ADD_IO_SEG(0x0001180050001088ull) -#define CVMX_PKO_MEM_DEBUG0 \ - CVMX_ADD_IO_SEG(0x0001180050001100ull) -#define CVMX_PKO_MEM_DEBUG1 \ - CVMX_ADD_IO_SEG(0x0001180050001108ull) -#define CVMX_PKO_MEM_DEBUG10 \ - CVMX_ADD_IO_SEG(0x0001180050001150ull) -#define CVMX_PKO_MEM_DEBUG11 \ - CVMX_ADD_IO_SEG(0x0001180050001158ull) -#define CVMX_PKO_MEM_DEBUG12 \ - CVMX_ADD_IO_SEG(0x0001180050001160ull) -#define CVMX_PKO_MEM_DEBUG13 \ - CVMX_ADD_IO_SEG(0x0001180050001168ull) -#define CVMX_PKO_MEM_DEBUG14 \ - CVMX_ADD_IO_SEG(0x0001180050001170ull) -#define CVMX_PKO_MEM_DEBUG2 \ - CVMX_ADD_IO_SEG(0x0001180050001110ull) -#define CVMX_PKO_MEM_DEBUG3 \ - CVMX_ADD_IO_SEG(0x0001180050001118ull) -#define CVMX_PKO_MEM_DEBUG4 \ - CVMX_ADD_IO_SEG(0x0001180050001120ull) -#define CVMX_PKO_MEM_DEBUG5 \ - CVMX_ADD_IO_SEG(0x0001180050001128ull) -#define CVMX_PKO_MEM_DEBUG6 \ - CVMX_ADD_IO_SEG(0x0001180050001130ull) -#define CVMX_PKO_MEM_DEBUG7 \ - CVMX_ADD_IO_SEG(0x0001180050001138ull) -#define CVMX_PKO_MEM_DEBUG8 \ - CVMX_ADD_IO_SEG(0x0001180050001140ull) -#define CVMX_PKO_MEM_DEBUG9 \ - CVMX_ADD_IO_SEG(0x0001180050001148ull) -#define CVMX_PKO_MEM_PORT_PTRS \ - CVMX_ADD_IO_SEG(0x0001180050001010ull) -#define CVMX_PKO_MEM_PORT_QOS \ - CVMX_ADD_IO_SEG(0x0001180050001018ull) -#define CVMX_PKO_MEM_PORT_RATE0 \ - CVMX_ADD_IO_SEG(0x0001180050001020ull) -#define CVMX_PKO_MEM_PORT_RATE1 \ - CVMX_ADD_IO_SEG(0x0001180050001028ull) -#define CVMX_PKO_MEM_QUEUE_PTRS \ - CVMX_ADD_IO_SEG(0x0001180050001000ull) -#define CVMX_PKO_MEM_QUEUE_QOS \ - CVMX_ADD_IO_SEG(0x0001180050001008ull) -#define CVMX_PKO_REG_BIST_RESULT \ - CVMX_ADD_IO_SEG(0x0001180050000080ull) -#define CVMX_PKO_REG_CMD_BUF \ - CVMX_ADD_IO_SEG(0x0001180050000010ull) -#define CVMX_PKO_REG_CRC_CTLX(offset) \ - CVMX_ADD_IO_SEG(0x0001180050000028ull + (((offset) & 1) * 8)) -#define CVMX_PKO_REG_CRC_ENABLE \ - CVMX_ADD_IO_SEG(0x0001180050000020ull) -#define CVMX_PKO_REG_CRC_IVX(offset) \ - CVMX_ADD_IO_SEG(0x0001180050000038ull + (((offset) & 1) * 8)) -#define CVMX_PKO_REG_DEBUG0 \ - CVMX_ADD_IO_SEG(0x0001180050000098ull) -#define CVMX_PKO_REG_DEBUG1 \ - CVMX_ADD_IO_SEG(0x00011800500000A0ull) -#define CVMX_PKO_REG_DEBUG2 \ - CVMX_ADD_IO_SEG(0x00011800500000A8ull) -#define CVMX_PKO_REG_DEBUG3 \ - CVMX_ADD_IO_SEG(0x00011800500000B0ull) -#define CVMX_PKO_REG_ENGINE_INFLIGHT \ - CVMX_ADD_IO_SEG(0x0001180050000050ull) -#define CVMX_PKO_REG_ENGINE_THRESH \ - CVMX_ADD_IO_SEG(0x0001180050000058ull) -#define CVMX_PKO_REG_ERROR \ - CVMX_ADD_IO_SEG(0x0001180050000088ull) -#define CVMX_PKO_REG_FLAGS \ - CVMX_ADD_IO_SEG(0x0001180050000000ull) -#define CVMX_PKO_REG_GMX_PORT_MODE \ - CVMX_ADD_IO_SEG(0x0001180050000018ull) -#define CVMX_PKO_REG_INT_MASK \ - CVMX_ADD_IO_SEG(0x0001180050000090ull) -#define CVMX_PKO_REG_QUEUE_MODE \ - CVMX_ADD_IO_SEG(0x0001180050000048ull) -#define CVMX_PKO_REG_QUEUE_PTRS1 \ - CVMX_ADD_IO_SEG(0x0001180050000100ull) -#define CVMX_PKO_REG_READ_IDX \ - CVMX_ADD_IO_SEG(0x0001180050000008ull) - -union cvmx_pko_mem_count0 { - uint64_t u64; - struct cvmx_pko_mem_count0_s { - uint64_t reserved_32_63:32; - uint64_t count:32; - } s; - struct cvmx_pko_mem_count0_s cn30xx; - struct cvmx_pko_mem_count0_s cn31xx; - struct cvmx_pko_mem_count0_s cn38xx; - struct cvmx_pko_mem_count0_s cn38xxp2; - struct cvmx_pko_mem_count0_s cn50xx; - struct cvmx_pko_mem_count0_s cn52xx; - struct cvmx_pko_mem_count0_s cn52xxp1; - struct cvmx_pko_mem_count0_s cn56xx; - struct cvmx_pko_mem_count0_s cn56xxp1; - struct cvmx_pko_mem_count0_s cn58xx; - struct cvmx_pko_mem_count0_s cn58xxp1; -}; - -union cvmx_pko_mem_count1 { - uint64_t u64; - struct cvmx_pko_mem_count1_s { - uint64_t reserved_48_63:16; - uint64_t count:48; - } s; - struct cvmx_pko_mem_count1_s cn30xx; - struct cvmx_pko_mem_count1_s cn31xx; - struct cvmx_pko_mem_count1_s cn38xx; - struct cvmx_pko_mem_count1_s cn38xxp2; - struct cvmx_pko_mem_count1_s cn50xx; - struct cvmx_pko_mem_count1_s cn52xx; - struct cvmx_pko_mem_count1_s cn52xxp1; - struct cvmx_pko_mem_count1_s cn56xx; - struct cvmx_pko_mem_count1_s cn56xxp1; - struct cvmx_pko_mem_count1_s cn58xx; - struct cvmx_pko_mem_count1_s cn58xxp1; -}; - -union cvmx_pko_mem_debug0 { - uint64_t u64; - struct cvmx_pko_mem_debug0_s { - uint64_t fau:28; - uint64_t cmd:14; - uint64_t segs:6; - uint64_t size:16; - } s; - struct cvmx_pko_mem_debug0_s cn30xx; - struct cvmx_pko_mem_debug0_s cn31xx; - struct cvmx_pko_mem_debug0_s cn38xx; - struct cvmx_pko_mem_debug0_s cn38xxp2; - struct cvmx_pko_mem_debug0_s cn50xx; - struct cvmx_pko_mem_debug0_s cn52xx; - struct cvmx_pko_mem_debug0_s cn52xxp1; - struct cvmx_pko_mem_debug0_s cn56xx; - struct cvmx_pko_mem_debug0_s cn56xxp1; - struct cvmx_pko_mem_debug0_s cn58xx; - struct cvmx_pko_mem_debug0_s cn58xxp1; -}; - -union cvmx_pko_mem_debug1 { - uint64_t u64; - struct cvmx_pko_mem_debug1_s { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t size:16; - uint64_t ptr:40; - } s; - struct cvmx_pko_mem_debug1_s cn30xx; - struct cvmx_pko_mem_debug1_s cn31xx; - struct cvmx_pko_mem_debug1_s cn38xx; - struct cvmx_pko_mem_debug1_s cn38xxp2; - struct cvmx_pko_mem_debug1_s cn50xx; - struct cvmx_pko_mem_debug1_s cn52xx; - struct cvmx_pko_mem_debug1_s cn52xxp1; - struct cvmx_pko_mem_debug1_s cn56xx; - struct cvmx_pko_mem_debug1_s cn56xxp1; - struct cvmx_pko_mem_debug1_s cn58xx; - struct cvmx_pko_mem_debug1_s cn58xxp1; -}; - -union cvmx_pko_mem_debug10 { - uint64_t u64; - struct cvmx_pko_mem_debug10_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_mem_debug10_cn30xx { - uint64_t fau:28; - uint64_t cmd:14; - uint64_t segs:6; - uint64_t size:16; - } cn30xx; - struct cvmx_pko_mem_debug10_cn30xx cn31xx; - struct cvmx_pko_mem_debug10_cn30xx cn38xx; - struct cvmx_pko_mem_debug10_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug10_cn50xx { - uint64_t reserved_49_63:15; - uint64_t ptrs1:17; - uint64_t reserved_17_31:15; - uint64_t ptrs2:17; - } cn50xx; - struct cvmx_pko_mem_debug10_cn50xx cn52xx; - struct cvmx_pko_mem_debug10_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug10_cn50xx cn56xx; - struct cvmx_pko_mem_debug10_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug10_cn50xx cn58xx; - struct cvmx_pko_mem_debug10_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug11 { - uint64_t u64; - struct cvmx_pko_mem_debug11_s { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t size:16; - uint64_t reserved_0_39:40; - } s; - struct cvmx_pko_mem_debug11_cn30xx { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t size:16; - uint64_t ptr:40; - } cn30xx; - struct cvmx_pko_mem_debug11_cn30xx cn31xx; - struct cvmx_pko_mem_debug11_cn30xx cn38xx; - struct cvmx_pko_mem_debug11_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug11_cn50xx { - uint64_t reserved_23_63:41; - uint64_t maj:1; - uint64_t uid:3; - uint64_t sop:1; - uint64_t len:1; - uint64_t chk:1; - uint64_t cnt:13; - uint64_t mod:3; - } cn50xx; - struct cvmx_pko_mem_debug11_cn50xx cn52xx; - struct cvmx_pko_mem_debug11_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug11_cn50xx cn56xx; - struct cvmx_pko_mem_debug11_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug11_cn50xx cn58xx; - struct cvmx_pko_mem_debug11_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug12 { - uint64_t u64; - struct cvmx_pko_mem_debug12_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_mem_debug12_cn30xx { - uint64_t data:64; - } cn30xx; - struct cvmx_pko_mem_debug12_cn30xx cn31xx; - struct cvmx_pko_mem_debug12_cn30xx cn38xx; - struct cvmx_pko_mem_debug12_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug12_cn50xx { - uint64_t fau:28; - uint64_t cmd:14; - uint64_t segs:6; - uint64_t size:16; - } cn50xx; - struct cvmx_pko_mem_debug12_cn50xx cn52xx; - struct cvmx_pko_mem_debug12_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug12_cn50xx cn56xx; - struct cvmx_pko_mem_debug12_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug12_cn50xx cn58xx; - struct cvmx_pko_mem_debug12_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug13 { - uint64_t u64; - struct cvmx_pko_mem_debug13_s { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t reserved_0_55:56; - } s; - struct cvmx_pko_mem_debug13_cn30xx { - uint64_t reserved_51_63:13; - uint64_t widx:17; - uint64_t ridx2:17; - uint64_t widx2:17; - } cn30xx; - struct cvmx_pko_mem_debug13_cn30xx cn31xx; - struct cvmx_pko_mem_debug13_cn30xx cn38xx; - struct cvmx_pko_mem_debug13_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug13_cn50xx { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t size:16; - uint64_t ptr:40; - } cn50xx; - struct cvmx_pko_mem_debug13_cn50xx cn52xx; - struct cvmx_pko_mem_debug13_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug13_cn50xx cn56xx; - struct cvmx_pko_mem_debug13_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug13_cn50xx cn58xx; - struct cvmx_pko_mem_debug13_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug14 { - uint64_t u64; - struct cvmx_pko_mem_debug14_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_mem_debug14_cn30xx { - uint64_t reserved_17_63:47; - uint64_t ridx:17; - } cn30xx; - struct cvmx_pko_mem_debug14_cn30xx cn31xx; - struct cvmx_pko_mem_debug14_cn30xx cn38xx; - struct cvmx_pko_mem_debug14_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug14_cn52xx { - uint64_t data:64; - } cn52xx; - struct cvmx_pko_mem_debug14_cn52xx cn52xxp1; - struct cvmx_pko_mem_debug14_cn52xx cn56xx; - struct cvmx_pko_mem_debug14_cn52xx cn56xxp1; -}; - -union cvmx_pko_mem_debug2 { - uint64_t u64; - struct cvmx_pko_mem_debug2_s { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t size:16; - uint64_t ptr:40; - } s; - struct cvmx_pko_mem_debug2_s cn30xx; - struct cvmx_pko_mem_debug2_s cn31xx; - struct cvmx_pko_mem_debug2_s cn38xx; - struct cvmx_pko_mem_debug2_s cn38xxp2; - struct cvmx_pko_mem_debug2_s cn50xx; - struct cvmx_pko_mem_debug2_s cn52xx; - struct cvmx_pko_mem_debug2_s cn52xxp1; - struct cvmx_pko_mem_debug2_s cn56xx; - struct cvmx_pko_mem_debug2_s cn56xxp1; - struct cvmx_pko_mem_debug2_s cn58xx; - struct cvmx_pko_mem_debug2_s cn58xxp1; -}; - -union cvmx_pko_mem_debug3 { - uint64_t u64; - struct cvmx_pko_mem_debug3_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_mem_debug3_cn30xx { - uint64_t i:1; - uint64_t back:4; - uint64_t pool:3; - uint64_t size:16; - uint64_t ptr:40; - } cn30xx; - struct cvmx_pko_mem_debug3_cn30xx cn31xx; - struct cvmx_pko_mem_debug3_cn30xx cn38xx; - struct cvmx_pko_mem_debug3_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug3_cn50xx { - uint64_t data:64; - } cn50xx; - struct cvmx_pko_mem_debug3_cn50xx cn52xx; - struct cvmx_pko_mem_debug3_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug3_cn50xx cn56xx; - struct cvmx_pko_mem_debug3_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug3_cn50xx cn58xx; - struct cvmx_pko_mem_debug3_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug4 { - uint64_t u64; - struct cvmx_pko_mem_debug4_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_mem_debug4_cn30xx { - uint64_t data:64; - } cn30xx; - struct cvmx_pko_mem_debug4_cn30xx cn31xx; - struct cvmx_pko_mem_debug4_cn30xx cn38xx; - struct cvmx_pko_mem_debug4_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug4_cn50xx { - uint64_t cmnd_segs:3; - uint64_t cmnd_siz:16; - uint64_t cmnd_off:6; - uint64_t uid:3; - uint64_t dread_sop:1; - uint64_t init_dwrite:1; - uint64_t chk_once:1; - uint64_t chk_mode:1; - uint64_t active:1; - uint64_t static_p:1; - uint64_t qos:3; - uint64_t qcb_ridx:5; - uint64_t qid_off_max:4; - uint64_t qid_off:4; - uint64_t qid_base:8; - uint64_t wait:1; - uint64_t minor:2; - uint64_t major:3; - } cn50xx; - struct cvmx_pko_mem_debug4_cn52xx { - uint64_t curr_siz:8; - uint64_t curr_off:16; - uint64_t cmnd_segs:6; - uint64_t cmnd_siz:16; - uint64_t cmnd_off:6; - uint64_t uid:2; - uint64_t dread_sop:1; - uint64_t init_dwrite:1; - uint64_t chk_once:1; - uint64_t chk_mode:1; - uint64_t wait:1; - uint64_t minor:2; - uint64_t major:3; - } cn52xx; - struct cvmx_pko_mem_debug4_cn52xx cn52xxp1; - struct cvmx_pko_mem_debug4_cn52xx cn56xx; - struct cvmx_pko_mem_debug4_cn52xx cn56xxp1; - struct cvmx_pko_mem_debug4_cn50xx cn58xx; - struct cvmx_pko_mem_debug4_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug5 { - uint64_t u64; - struct cvmx_pko_mem_debug5_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_mem_debug5_cn30xx { - uint64_t dwri_mod:1; - uint64_t dwri_sop:1; - uint64_t dwri_len:1; - uint64_t dwri_cnt:13; - uint64_t cmnd_siz:16; - uint64_t uid:1; - uint64_t xfer_wor:1; - uint64_t xfer_dwr:1; - uint64_t cbuf_fre:1; - uint64_t reserved_27_27:1; - uint64_t chk_mode:1; - uint64_t active:1; - uint64_t qos:3; - uint64_t qcb_ridx:5; - uint64_t qid_off:3; - uint64_t qid_base:7; - uint64_t wait:1; - uint64_t minor:2; - uint64_t major:4; - } cn30xx; - struct cvmx_pko_mem_debug5_cn30xx cn31xx; - struct cvmx_pko_mem_debug5_cn30xx cn38xx; - struct cvmx_pko_mem_debug5_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug5_cn50xx { - uint64_t curr_ptr:29; - uint64_t curr_siz:16; - uint64_t curr_off:16; - uint64_t cmnd_segs:3; - } cn50xx; - struct cvmx_pko_mem_debug5_cn52xx { - uint64_t reserved_54_63:10; - uint64_t nxt_inflt:6; - uint64_t curr_ptr:40; - uint64_t curr_siz:8; - } cn52xx; - struct cvmx_pko_mem_debug5_cn52xx cn52xxp1; - struct cvmx_pko_mem_debug5_cn52xx cn56xx; - struct cvmx_pko_mem_debug5_cn52xx cn56xxp1; - struct cvmx_pko_mem_debug5_cn50xx cn58xx; - struct cvmx_pko_mem_debug5_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug6 { - uint64_t u64; - struct cvmx_pko_mem_debug6_s { - uint64_t reserved_37_63:27; - uint64_t qid_offres:4; - uint64_t qid_offths:4; - uint64_t preempter:1; - uint64_t preemptee:1; - uint64_t preempted:1; - uint64_t active:1; - uint64_t statc:1; - uint64_t qos:3; - uint64_t qcb_ridx:5; - uint64_t qid_offmax:4; - uint64_t reserved_0_11:12; - } s; - struct cvmx_pko_mem_debug6_cn30xx { - uint64_t reserved_11_63:53; - uint64_t qid_offm:3; - uint64_t static_p:1; - uint64_t work_min:3; - uint64_t dwri_chk:1; - uint64_t dwri_uid:1; - uint64_t dwri_mod:2; - } cn30xx; - struct cvmx_pko_mem_debug6_cn30xx cn31xx; - struct cvmx_pko_mem_debug6_cn30xx cn38xx; - struct cvmx_pko_mem_debug6_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug6_cn50xx { - uint64_t reserved_11_63:53; - uint64_t curr_ptr:11; - } cn50xx; - struct cvmx_pko_mem_debug6_cn52xx { - uint64_t reserved_37_63:27; - uint64_t qid_offres:4; - uint64_t qid_offths:4; - uint64_t preempter:1; - uint64_t preemptee:1; - uint64_t preempted:1; - uint64_t active:1; - uint64_t statc:1; - uint64_t qos:3; - uint64_t qcb_ridx:5; - uint64_t qid_offmax:4; - uint64_t qid_off:4; - uint64_t qid_base:8; - } cn52xx; - struct cvmx_pko_mem_debug6_cn52xx cn52xxp1; - struct cvmx_pko_mem_debug6_cn52xx cn56xx; - struct cvmx_pko_mem_debug6_cn52xx cn56xxp1; - struct cvmx_pko_mem_debug6_cn50xx cn58xx; - struct cvmx_pko_mem_debug6_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug7 { - uint64_t u64; - struct cvmx_pko_mem_debug7_s { - uint64_t qos:5; - uint64_t tail:1; - uint64_t reserved_0_57:58; - } s; - struct cvmx_pko_mem_debug7_cn30xx { - uint64_t reserved_58_63:6; - uint64_t dwb:9; - uint64_t start:33; - uint64_t size:16; - } cn30xx; - struct cvmx_pko_mem_debug7_cn30xx cn31xx; - struct cvmx_pko_mem_debug7_cn30xx cn38xx; - struct cvmx_pko_mem_debug7_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug7_cn50xx { - uint64_t qos:5; - uint64_t tail:1; - uint64_t buf_siz:13; - uint64_t buf_ptr:33; - uint64_t qcb_widx:6; - uint64_t qcb_ridx:6; - } cn50xx; - struct cvmx_pko_mem_debug7_cn50xx cn52xx; - struct cvmx_pko_mem_debug7_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug7_cn50xx cn56xx; - struct cvmx_pko_mem_debug7_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug7_cn50xx cn58xx; - struct cvmx_pko_mem_debug7_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug8 { - uint64_t u64; - struct cvmx_pko_mem_debug8_s { - uint64_t reserved_59_63:5; - uint64_t tail:1; - uint64_t buf_siz:13; - uint64_t reserved_0_44:45; - } s; - struct cvmx_pko_mem_debug8_cn30xx { - uint64_t qos:5; - uint64_t tail:1; - uint64_t buf_siz:13; - uint64_t buf_ptr:33; - uint64_t qcb_widx:6; - uint64_t qcb_ridx:6; - } cn30xx; - struct cvmx_pko_mem_debug8_cn30xx cn31xx; - struct cvmx_pko_mem_debug8_cn30xx cn38xx; - struct cvmx_pko_mem_debug8_cn30xx cn38xxp2; - struct cvmx_pko_mem_debug8_cn50xx { - uint64_t reserved_28_63:36; - uint64_t doorbell:20; - uint64_t reserved_6_7:2; - uint64_t static_p:1; - uint64_t s_tail:1; - uint64_t static_q:1; - uint64_t qos:3; - } cn50xx; - struct cvmx_pko_mem_debug8_cn52xx { - uint64_t reserved_29_63:35; - uint64_t preempter:1; - uint64_t doorbell:20; - uint64_t reserved_7_7:1; - uint64_t preemptee:1; - uint64_t static_p:1; - uint64_t s_tail:1; - uint64_t static_q:1; - uint64_t qos:3; - } cn52xx; - struct cvmx_pko_mem_debug8_cn52xx cn52xxp1; - struct cvmx_pko_mem_debug8_cn52xx cn56xx; - struct cvmx_pko_mem_debug8_cn52xx cn56xxp1; - struct cvmx_pko_mem_debug8_cn50xx cn58xx; - struct cvmx_pko_mem_debug8_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_debug9 { - uint64_t u64; - struct cvmx_pko_mem_debug9_s { - uint64_t reserved_49_63:15; - uint64_t ptrs0:17; - uint64_t reserved_0_31:32; - } s; - struct cvmx_pko_mem_debug9_cn30xx { - uint64_t reserved_28_63:36; - uint64_t doorbell:20; - uint64_t reserved_5_7:3; - uint64_t s_tail:1; - uint64_t static_q:1; - uint64_t qos:3; - } cn30xx; - struct cvmx_pko_mem_debug9_cn30xx cn31xx; - struct cvmx_pko_mem_debug9_cn38xx { - uint64_t reserved_28_63:36; - uint64_t doorbell:20; - uint64_t reserved_6_7:2; - uint64_t static_p:1; - uint64_t s_tail:1; - uint64_t static_q:1; - uint64_t qos:3; - } cn38xx; - struct cvmx_pko_mem_debug9_cn38xx cn38xxp2; - struct cvmx_pko_mem_debug9_cn50xx { - uint64_t reserved_49_63:15; - uint64_t ptrs0:17; - uint64_t reserved_17_31:15; - uint64_t ptrs3:17; - } cn50xx; - struct cvmx_pko_mem_debug9_cn50xx cn52xx; - struct cvmx_pko_mem_debug9_cn50xx cn52xxp1; - struct cvmx_pko_mem_debug9_cn50xx cn56xx; - struct cvmx_pko_mem_debug9_cn50xx cn56xxp1; - struct cvmx_pko_mem_debug9_cn50xx cn58xx; - struct cvmx_pko_mem_debug9_cn50xx cn58xxp1; -}; - -union cvmx_pko_mem_port_ptrs { - uint64_t u64; - struct cvmx_pko_mem_port_ptrs_s { - uint64_t reserved_62_63:2; - uint64_t static_p:1; - uint64_t qos_mask:8; - uint64_t reserved_16_52:37; - uint64_t bp_port:6; - uint64_t eid:4; - uint64_t pid:6; - } s; - struct cvmx_pko_mem_port_ptrs_s cn52xx; - struct cvmx_pko_mem_port_ptrs_s cn52xxp1; - struct cvmx_pko_mem_port_ptrs_s cn56xx; - struct cvmx_pko_mem_port_ptrs_s cn56xxp1; -}; - -union cvmx_pko_mem_port_qos { - uint64_t u64; - struct cvmx_pko_mem_port_qos_s { - uint64_t reserved_61_63:3; - uint64_t qos_mask:8; - uint64_t reserved_10_52:43; - uint64_t eid:4; - uint64_t pid:6; - } s; - struct cvmx_pko_mem_port_qos_s cn52xx; - struct cvmx_pko_mem_port_qos_s cn52xxp1; - struct cvmx_pko_mem_port_qos_s cn56xx; - struct cvmx_pko_mem_port_qos_s cn56xxp1; -}; - -union cvmx_pko_mem_port_rate0 { - uint64_t u64; - struct cvmx_pko_mem_port_rate0_s { - uint64_t reserved_51_63:13; - uint64_t rate_word:19; - uint64_t rate_pkt:24; - uint64_t reserved_6_7:2; - uint64_t pid:6; - } s; - struct cvmx_pko_mem_port_rate0_s cn52xx; - struct cvmx_pko_mem_port_rate0_s cn52xxp1; - struct cvmx_pko_mem_port_rate0_s cn56xx; - struct cvmx_pko_mem_port_rate0_s cn56xxp1; -}; - -union cvmx_pko_mem_port_rate1 { - uint64_t u64; - struct cvmx_pko_mem_port_rate1_s { - uint64_t reserved_32_63:32; - uint64_t rate_lim:24; - uint64_t reserved_6_7:2; - uint64_t pid:6; - } s; - struct cvmx_pko_mem_port_rate1_s cn52xx; - struct cvmx_pko_mem_port_rate1_s cn52xxp1; - struct cvmx_pko_mem_port_rate1_s cn56xx; - struct cvmx_pko_mem_port_rate1_s cn56xxp1; -}; - -union cvmx_pko_mem_queue_ptrs { - uint64_t u64; - struct cvmx_pko_mem_queue_ptrs_s { - uint64_t s_tail:1; - uint64_t static_p:1; - uint64_t static_q:1; - uint64_t qos_mask:8; - uint64_t buf_ptr:36; - uint64_t tail:1; - uint64_t index:3; - uint64_t port:6; - uint64_t queue:7; - } s; - struct cvmx_pko_mem_queue_ptrs_s cn30xx; - struct cvmx_pko_mem_queue_ptrs_s cn31xx; - struct cvmx_pko_mem_queue_ptrs_s cn38xx; - struct cvmx_pko_mem_queue_ptrs_s cn38xxp2; - struct cvmx_pko_mem_queue_ptrs_s cn50xx; - struct cvmx_pko_mem_queue_ptrs_s cn52xx; - struct cvmx_pko_mem_queue_ptrs_s cn52xxp1; - struct cvmx_pko_mem_queue_ptrs_s cn56xx; - struct cvmx_pko_mem_queue_ptrs_s cn56xxp1; - struct cvmx_pko_mem_queue_ptrs_s cn58xx; - struct cvmx_pko_mem_queue_ptrs_s cn58xxp1; -}; - -union cvmx_pko_mem_queue_qos { - uint64_t u64; - struct cvmx_pko_mem_queue_qos_s { - uint64_t reserved_61_63:3; - uint64_t qos_mask:8; - uint64_t reserved_13_52:40; - uint64_t pid:6; - uint64_t qid:7; - } s; - struct cvmx_pko_mem_queue_qos_s cn30xx; - struct cvmx_pko_mem_queue_qos_s cn31xx; - struct cvmx_pko_mem_queue_qos_s cn38xx; - struct cvmx_pko_mem_queue_qos_s cn38xxp2; - struct cvmx_pko_mem_queue_qos_s cn50xx; - struct cvmx_pko_mem_queue_qos_s cn52xx; - struct cvmx_pko_mem_queue_qos_s cn52xxp1; - struct cvmx_pko_mem_queue_qos_s cn56xx; - struct cvmx_pko_mem_queue_qos_s cn56xxp1; - struct cvmx_pko_mem_queue_qos_s cn58xx; - struct cvmx_pko_mem_queue_qos_s cn58xxp1; -}; - -union cvmx_pko_reg_bist_result { - uint64_t u64; - struct cvmx_pko_reg_bist_result_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_pko_reg_bist_result_cn30xx { - uint64_t reserved_27_63:37; - uint64_t psb2:5; - uint64_t count:1; - uint64_t rif:1; - uint64_t wif:1; - uint64_t ncb:1; - uint64_t out:1; - uint64_t crc:1; - uint64_t chk:1; - uint64_t qsb:2; - uint64_t qcb:2; - uint64_t pdb:4; - uint64_t psb:7; - } cn30xx; - struct cvmx_pko_reg_bist_result_cn30xx cn31xx; - struct cvmx_pko_reg_bist_result_cn30xx cn38xx; - struct cvmx_pko_reg_bist_result_cn30xx cn38xxp2; - struct cvmx_pko_reg_bist_result_cn50xx { - uint64_t reserved_33_63:31; - uint64_t csr:1; - uint64_t iob:1; - uint64_t out_crc:1; - uint64_t out_ctl:3; - uint64_t out_sta:1; - uint64_t out_wif:1; - uint64_t prt_chk:3; - uint64_t prt_nxt:1; - uint64_t prt_psb:6; - uint64_t ncb_inb:2; - uint64_t prt_qcb:2; - uint64_t prt_qsb:3; - uint64_t dat_dat:4; - uint64_t dat_ptr:4; - } cn50xx; - struct cvmx_pko_reg_bist_result_cn52xx { - uint64_t reserved_35_63:29; - uint64_t csr:1; - uint64_t iob:1; - uint64_t out_dat:1; - uint64_t out_ctl:3; - uint64_t out_sta:1; - uint64_t out_wif:1; - uint64_t prt_chk:3; - uint64_t prt_nxt:1; - uint64_t prt_psb:8; - uint64_t ncb_inb:2; - uint64_t prt_qcb:2; - uint64_t prt_qsb:3; - uint64_t prt_ctl:2; - uint64_t dat_dat:2; - uint64_t dat_ptr:4; - } cn52xx; - struct cvmx_pko_reg_bist_result_cn52xx cn52xxp1; - struct cvmx_pko_reg_bist_result_cn52xx cn56xx; - struct cvmx_pko_reg_bist_result_cn52xx cn56xxp1; - struct cvmx_pko_reg_bist_result_cn50xx cn58xx; - struct cvmx_pko_reg_bist_result_cn50xx cn58xxp1; -}; - -union cvmx_pko_reg_cmd_buf { - uint64_t u64; - struct cvmx_pko_reg_cmd_buf_s { - uint64_t reserved_23_63:41; - uint64_t pool:3; - uint64_t reserved_13_19:7; - uint64_t size:13; - } s; - struct cvmx_pko_reg_cmd_buf_s cn30xx; - struct cvmx_pko_reg_cmd_buf_s cn31xx; - struct cvmx_pko_reg_cmd_buf_s cn38xx; - struct cvmx_pko_reg_cmd_buf_s cn38xxp2; - struct cvmx_pko_reg_cmd_buf_s cn50xx; - struct cvmx_pko_reg_cmd_buf_s cn52xx; - struct cvmx_pko_reg_cmd_buf_s cn52xxp1; - struct cvmx_pko_reg_cmd_buf_s cn56xx; - struct cvmx_pko_reg_cmd_buf_s cn56xxp1; - struct cvmx_pko_reg_cmd_buf_s cn58xx; - struct cvmx_pko_reg_cmd_buf_s cn58xxp1; -}; - -union cvmx_pko_reg_crc_ctlx { - uint64_t u64; - struct cvmx_pko_reg_crc_ctlx_s { - uint64_t reserved_2_63:62; - uint64_t invres:1; - uint64_t refin:1; - } s; - struct cvmx_pko_reg_crc_ctlx_s cn38xx; - struct cvmx_pko_reg_crc_ctlx_s cn38xxp2; - struct cvmx_pko_reg_crc_ctlx_s cn58xx; - struct cvmx_pko_reg_crc_ctlx_s cn58xxp1; -}; - -union cvmx_pko_reg_crc_enable { - uint64_t u64; - struct cvmx_pko_reg_crc_enable_s { - uint64_t reserved_32_63:32; - uint64_t enable:32; - } s; - struct cvmx_pko_reg_crc_enable_s cn38xx; - struct cvmx_pko_reg_crc_enable_s cn38xxp2; - struct cvmx_pko_reg_crc_enable_s cn58xx; - struct cvmx_pko_reg_crc_enable_s cn58xxp1; -}; - -union cvmx_pko_reg_crc_ivx { - uint64_t u64; - struct cvmx_pko_reg_crc_ivx_s { - uint64_t reserved_32_63:32; - uint64_t iv:32; - } s; - struct cvmx_pko_reg_crc_ivx_s cn38xx; - struct cvmx_pko_reg_crc_ivx_s cn38xxp2; - struct cvmx_pko_reg_crc_ivx_s cn58xx; - struct cvmx_pko_reg_crc_ivx_s cn58xxp1; -}; - -union cvmx_pko_reg_debug0 { - uint64_t u64; - struct cvmx_pko_reg_debug0_s { - uint64_t asserts:64; - } s; - struct cvmx_pko_reg_debug0_cn30xx { - uint64_t reserved_17_63:47; - uint64_t asserts:17; - } cn30xx; - struct cvmx_pko_reg_debug0_cn30xx cn31xx; - struct cvmx_pko_reg_debug0_cn30xx cn38xx; - struct cvmx_pko_reg_debug0_cn30xx cn38xxp2; - struct cvmx_pko_reg_debug0_s cn50xx; - struct cvmx_pko_reg_debug0_s cn52xx; - struct cvmx_pko_reg_debug0_s cn52xxp1; - struct cvmx_pko_reg_debug0_s cn56xx; - struct cvmx_pko_reg_debug0_s cn56xxp1; - struct cvmx_pko_reg_debug0_s cn58xx; - struct cvmx_pko_reg_debug0_s cn58xxp1; -}; - -union cvmx_pko_reg_debug1 { - uint64_t u64; - struct cvmx_pko_reg_debug1_s { - uint64_t asserts:64; - } s; - struct cvmx_pko_reg_debug1_s cn50xx; - struct cvmx_pko_reg_debug1_s cn52xx; - struct cvmx_pko_reg_debug1_s cn52xxp1; - struct cvmx_pko_reg_debug1_s cn56xx; - struct cvmx_pko_reg_debug1_s cn56xxp1; - struct cvmx_pko_reg_debug1_s cn58xx; - struct cvmx_pko_reg_debug1_s cn58xxp1; -}; - -union cvmx_pko_reg_debug2 { - uint64_t u64; - struct cvmx_pko_reg_debug2_s { - uint64_t asserts:64; - } s; - struct cvmx_pko_reg_debug2_s cn50xx; - struct cvmx_pko_reg_debug2_s cn52xx; - struct cvmx_pko_reg_debug2_s cn52xxp1; - struct cvmx_pko_reg_debug2_s cn56xx; - struct cvmx_pko_reg_debug2_s cn56xxp1; - struct cvmx_pko_reg_debug2_s cn58xx; - struct cvmx_pko_reg_debug2_s cn58xxp1; -}; - -union cvmx_pko_reg_debug3 { - uint64_t u64; - struct cvmx_pko_reg_debug3_s { - uint64_t asserts:64; - } s; - struct cvmx_pko_reg_debug3_s cn50xx; - struct cvmx_pko_reg_debug3_s cn52xx; - struct cvmx_pko_reg_debug3_s cn52xxp1; - struct cvmx_pko_reg_debug3_s cn56xx; - struct cvmx_pko_reg_debug3_s cn56xxp1; - struct cvmx_pko_reg_debug3_s cn58xx; - struct cvmx_pko_reg_debug3_s cn58xxp1; -}; - -union cvmx_pko_reg_engine_inflight { - uint64_t u64; - struct cvmx_pko_reg_engine_inflight_s { - uint64_t reserved_40_63:24; - uint64_t engine9:4; - uint64_t engine8:4; - uint64_t engine7:4; - uint64_t engine6:4; - uint64_t engine5:4; - uint64_t engine4:4; - uint64_t engine3:4; - uint64_t engine2:4; - uint64_t engine1:4; - uint64_t engine0:4; - } s; - struct cvmx_pko_reg_engine_inflight_s cn52xx; - struct cvmx_pko_reg_engine_inflight_s cn52xxp1; - struct cvmx_pko_reg_engine_inflight_s cn56xx; - struct cvmx_pko_reg_engine_inflight_s cn56xxp1; -}; - -union cvmx_pko_reg_engine_thresh { - uint64_t u64; - struct cvmx_pko_reg_engine_thresh_s { - uint64_t reserved_10_63:54; - uint64_t mask:10; - } s; - struct cvmx_pko_reg_engine_thresh_s cn52xx; - struct cvmx_pko_reg_engine_thresh_s cn52xxp1; - struct cvmx_pko_reg_engine_thresh_s cn56xx; - struct cvmx_pko_reg_engine_thresh_s cn56xxp1; -}; - -union cvmx_pko_reg_error { - uint64_t u64; - struct cvmx_pko_reg_error_s { - uint64_t reserved_3_63:61; - uint64_t currzero:1; - uint64_t doorbell:1; - uint64_t parity:1; - } s; - struct cvmx_pko_reg_error_cn30xx { - uint64_t reserved_2_63:62; - uint64_t doorbell:1; - uint64_t parity:1; - } cn30xx; - struct cvmx_pko_reg_error_cn30xx cn31xx; - struct cvmx_pko_reg_error_cn30xx cn38xx; - struct cvmx_pko_reg_error_cn30xx cn38xxp2; - struct cvmx_pko_reg_error_s cn50xx; - struct cvmx_pko_reg_error_s cn52xx; - struct cvmx_pko_reg_error_s cn52xxp1; - struct cvmx_pko_reg_error_s cn56xx; - struct cvmx_pko_reg_error_s cn56xxp1; - struct cvmx_pko_reg_error_s cn58xx; - struct cvmx_pko_reg_error_s cn58xxp1; -}; - -union cvmx_pko_reg_flags { - uint64_t u64; - struct cvmx_pko_reg_flags_s { - uint64_t reserved_4_63:60; - uint64_t reset:1; - uint64_t store_be:1; - uint64_t ena_dwb:1; - uint64_t ena_pko:1; - } s; - struct cvmx_pko_reg_flags_s cn30xx; - struct cvmx_pko_reg_flags_s cn31xx; - struct cvmx_pko_reg_flags_s cn38xx; - struct cvmx_pko_reg_flags_s cn38xxp2; - struct cvmx_pko_reg_flags_s cn50xx; - struct cvmx_pko_reg_flags_s cn52xx; - struct cvmx_pko_reg_flags_s cn52xxp1; - struct cvmx_pko_reg_flags_s cn56xx; - struct cvmx_pko_reg_flags_s cn56xxp1; - struct cvmx_pko_reg_flags_s cn58xx; - struct cvmx_pko_reg_flags_s cn58xxp1; -}; - -union cvmx_pko_reg_gmx_port_mode { - uint64_t u64; - struct cvmx_pko_reg_gmx_port_mode_s { - uint64_t reserved_6_63:58; - uint64_t mode1:3; - uint64_t mode0:3; - } s; - struct cvmx_pko_reg_gmx_port_mode_s cn30xx; - struct cvmx_pko_reg_gmx_port_mode_s cn31xx; - struct cvmx_pko_reg_gmx_port_mode_s cn38xx; - struct cvmx_pko_reg_gmx_port_mode_s cn38xxp2; - struct cvmx_pko_reg_gmx_port_mode_s cn50xx; - struct cvmx_pko_reg_gmx_port_mode_s cn52xx; - struct cvmx_pko_reg_gmx_port_mode_s cn52xxp1; - struct cvmx_pko_reg_gmx_port_mode_s cn56xx; - struct cvmx_pko_reg_gmx_port_mode_s cn56xxp1; - struct cvmx_pko_reg_gmx_port_mode_s cn58xx; - struct cvmx_pko_reg_gmx_port_mode_s cn58xxp1; -}; - -union cvmx_pko_reg_int_mask { - uint64_t u64; - struct cvmx_pko_reg_int_mask_s { - uint64_t reserved_3_63:61; - uint64_t currzero:1; - uint64_t doorbell:1; - uint64_t parity:1; - } s; - struct cvmx_pko_reg_int_mask_cn30xx { - uint64_t reserved_2_63:62; - uint64_t doorbell:1; - uint64_t parity:1; - } cn30xx; - struct cvmx_pko_reg_int_mask_cn30xx cn31xx; - struct cvmx_pko_reg_int_mask_cn30xx cn38xx; - struct cvmx_pko_reg_int_mask_cn30xx cn38xxp2; - struct cvmx_pko_reg_int_mask_s cn50xx; - struct cvmx_pko_reg_int_mask_s cn52xx; - struct cvmx_pko_reg_int_mask_s cn52xxp1; - struct cvmx_pko_reg_int_mask_s cn56xx; - struct cvmx_pko_reg_int_mask_s cn56xxp1; - struct cvmx_pko_reg_int_mask_s cn58xx; - struct cvmx_pko_reg_int_mask_s cn58xxp1; -}; - -union cvmx_pko_reg_queue_mode { - uint64_t u64; - struct cvmx_pko_reg_queue_mode_s { - uint64_t reserved_2_63:62; - uint64_t mode:2; - } s; - struct cvmx_pko_reg_queue_mode_s cn30xx; - struct cvmx_pko_reg_queue_mode_s cn31xx; - struct cvmx_pko_reg_queue_mode_s cn38xx; - struct cvmx_pko_reg_queue_mode_s cn38xxp2; - struct cvmx_pko_reg_queue_mode_s cn50xx; - struct cvmx_pko_reg_queue_mode_s cn52xx; - struct cvmx_pko_reg_queue_mode_s cn52xxp1; - struct cvmx_pko_reg_queue_mode_s cn56xx; - struct cvmx_pko_reg_queue_mode_s cn56xxp1; - struct cvmx_pko_reg_queue_mode_s cn58xx; - struct cvmx_pko_reg_queue_mode_s cn58xxp1; -}; - -union cvmx_pko_reg_queue_ptrs1 { - uint64_t u64; - struct cvmx_pko_reg_queue_ptrs1_s { - uint64_t reserved_2_63:62; - uint64_t idx3:1; - uint64_t qid7:1; - } s; - struct cvmx_pko_reg_queue_ptrs1_s cn50xx; - struct cvmx_pko_reg_queue_ptrs1_s cn52xx; - struct cvmx_pko_reg_queue_ptrs1_s cn52xxp1; - struct cvmx_pko_reg_queue_ptrs1_s cn56xx; - struct cvmx_pko_reg_queue_ptrs1_s cn56xxp1; - struct cvmx_pko_reg_queue_ptrs1_s cn58xx; - struct cvmx_pko_reg_queue_ptrs1_s cn58xxp1; -}; - -union cvmx_pko_reg_read_idx { - uint64_t u64; - struct cvmx_pko_reg_read_idx_s { - uint64_t reserved_16_63:48; - uint64_t inc:8; - uint64_t index:8; - } s; - struct cvmx_pko_reg_read_idx_s cn30xx; - struct cvmx_pko_reg_read_idx_s cn31xx; - struct cvmx_pko_reg_read_idx_s cn38xx; - struct cvmx_pko_reg_read_idx_s cn38xxp2; - struct cvmx_pko_reg_read_idx_s cn50xx; - struct cvmx_pko_reg_read_idx_s cn52xx; - struct cvmx_pko_reg_read_idx_s cn52xxp1; - struct cvmx_pko_reg_read_idx_s cn56xx; - struct cvmx_pko_reg_read_idx_s cn56xxp1; - struct cvmx_pko_reg_read_idx_s cn58xx; - struct cvmx_pko_reg_read_idx_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-pko.c b/drivers/staging/octeon/cvmx-pko.c deleted file mode 100644 index 50a2c9bd5a55..000000000000 --- a/drivers/staging/octeon/cvmx-pko.c +++ /dev/null @@ -1,506 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * Support library for the hardware Packet Output unit. - */ - -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" -#include "cvmx-pko.h" -#include "cvmx-helper.h" - -/** - * Internal state of packet output - */ - -/** - * Call before any other calls to initialize the packet - * output system. This does chip global config, and should only be - * done by one core. - */ - -void cvmx_pko_initialize_global(void) -{ - int i; - uint64_t priority = 8; - union cvmx_pko_reg_cmd_buf config; - - /* - * Set the size of the PKO command buffers to an odd number of - * 64bit words. This allows the normal two word send to stay - * aligned and never span a command word buffer. - */ - config.u64 = 0; - config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL; - config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1; - - cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); - - for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) - cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, - &priority); - - /* - * If we aren't using all of the queues optimize PKO's - * internal memory. - */ - if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) - || OCTEON_IS_MODEL(OCTEON_CN56XX) - || OCTEON_IS_MODEL(OCTEON_CN52XX)) { - int num_interfaces = cvmx_helper_get_number_of_interfaces(); - int last_port = - cvmx_helper_get_last_ipd_port(num_interfaces - 1); - int max_queues = - cvmx_pko_get_base_queue(last_port) + - cvmx_pko_get_num_queues(last_port); - if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { - if (max_queues <= 32) - cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); - else if (max_queues <= 64) - cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); - } else { - if (max_queues <= 64) - cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2); - else if (max_queues <= 128) - cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1); - } - } -} - -/** - * This function does per-core initialization required by the PKO routines. - * This must be called on all cores that will do packet output, and must - * be called after the FPA has been initialized and filled with pages. - * - * Returns 0 on success - * !0 on failure - */ -int cvmx_pko_initialize_local(void) -{ - /* Nothing to do */ - return 0; -} - -/** - * Enables the packet output hardware. It must already be - * configured. - */ -void cvmx_pko_enable(void) -{ - union cvmx_pko_reg_flags flags; - - flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); - if (flags.s.ena_pko) - cvmx_dprintf - ("Warning: Enabling PKO when PKO already enabled.\n"); - - flags.s.ena_dwb = 1; - flags.s.ena_pko = 1; - /* - * always enable big endian for 3-word command. Does nothing - * for 2-word. - */ - flags.s.store_be = 1; - cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64); -} - -/** - * Disables the packet output. Does not affect any configuration. - */ -void cvmx_pko_disable(void) -{ - union cvmx_pko_reg_flags pko_reg_flags; - pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); - pko_reg_flags.s.ena_pko = 0; - cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); -} - - -/** - * Reset the packet output. - */ -static void __cvmx_pko_reset(void) -{ - union cvmx_pko_reg_flags pko_reg_flags; - pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS); - pko_reg_flags.s.reset = 1; - cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64); -} - -/** - * Shutdown and free resources required by packet output. - */ -void cvmx_pko_shutdown(void) -{ - union cvmx_pko_mem_queue_ptrs config; - int queue; - - cvmx_pko_disable(); - - for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) { - config.u64 = 0; - config.s.tail = 1; - config.s.index = 0; - config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID; - config.s.queue = queue & 0x7f; - config.s.qos_mask = 0; - config.s.buf_ptr = 0; - if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) { - union cvmx_pko_reg_queue_ptrs1 config1; - config1.u64 = 0; - config1.s.qid7 = queue >> 7; - cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); - } - cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); - cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue)); - } - __cvmx_pko_reset(); -} - -/** - * Configure a output port and the associated queues for use. - * - * @port: Port to configure. - * @base_queue: First queue number to associate with this port. - * @num_queues: Number of queues to associate with this port - * @priority: Array of priority levels for each queue. Values are - * allowed to be 0-8. A value of 8 get 8 times the traffic - * of a value of 1. A value of 0 indicates that no rounds - * will be participated in. These priorities can be changed - * on the fly while the pko is enabled. A priority of 9 - * indicates that static priority should be used. If static - * priority is used all queues with static priority must be - * contiguous starting at the base_queue, and lower numbered - * queues have higher priority than higher numbered queues. - * There must be num_queues elements in the array. - */ -cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, - uint64_t num_queues, - const uint64_t priority[]) -{ - cvmx_pko_status_t result_code; - uint64_t queue; - union cvmx_pko_mem_queue_ptrs config; - union cvmx_pko_reg_queue_ptrs1 config1; - int static_priority_base = -1; - int static_priority_end = -1; - - if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) - && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { - cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", - (unsigned long long)port); - return CVMX_PKO_INVALID_PORT; - } - - if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) { - cvmx_dprintf - ("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n", - (unsigned long long)(base_queue + num_queues)); - return CVMX_PKO_INVALID_QUEUE; - } - - if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) { - /* - * Validate the static queue priority setup and set - * static_priority_base and static_priority_end - * accordingly. - */ - for (queue = 0; queue < num_queues; queue++) { - /* Find first queue of static priority */ - if (static_priority_base == -1 - && priority[queue] == - CVMX_PKO_QUEUE_STATIC_PRIORITY) - static_priority_base = queue; - /* Find last queue of static priority */ - if (static_priority_base != -1 - && static_priority_end == -1 - && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY - && queue) - static_priority_end = queue - 1; - else if (static_priority_base != -1 - && static_priority_end == -1 - && queue == num_queues - 1) - /* all queues are static priority */ - static_priority_end = queue; - /* - * Check to make sure all static priority - * queues are contiguous. Also catches some - * cases of static priorites not starting at - * queue 0. - */ - if (static_priority_end != -1 - && (int)queue > static_priority_end - && priority[queue] == - CVMX_PKO_QUEUE_STATIC_PRIORITY) { - cvmx_dprintf("ERROR: cvmx_pko_config_port: " - "Static priority queues aren't " - "contiguous or don't start at " - "base queue. q: %d, eq: %d\n", - (int)queue, static_priority_end); - return CVMX_PKO_INVALID_PRIORITY; - } - } - if (static_priority_base > 0) { - cvmx_dprintf("ERROR: cvmx_pko_config_port: Static " - "priority queues don't start at base " - "queue. sq: %d\n", - static_priority_base); - return CVMX_PKO_INVALID_PRIORITY; - } -#if 0 - cvmx_dprintf("Port %d: Static priority queue base: %d, " - "end: %d\n", port, - static_priority_base, static_priority_end); -#endif - } - /* - * At this point, static_priority_base and static_priority_end - * are either both -1, or are valid start/end queue - * numbers. - */ - - result_code = CVMX_PKO_SUCCESS; - -#ifdef PKO_DEBUG - cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues, - CVMX_PKO_QUEUES_PER_PORT_INTERFACE0, - CVMX_PKO_QUEUES_PER_PORT_INTERFACE1); -#endif - - for (queue = 0; queue < num_queues; queue++) { - uint64_t *buf_ptr = NULL; - - config1.u64 = 0; - config1.s.idx3 = queue >> 3; - config1.s.qid7 = (base_queue + queue) >> 7; - - config.u64 = 0; - config.s.tail = queue == (num_queues - 1); - config.s.index = queue; - config.s.port = port; - config.s.queue = base_queue + queue; - - if (!cvmx_octeon_is_pass1()) { - config.s.static_p = static_priority_base >= 0; - config.s.static_q = (int)queue <= static_priority_end; - config.s.s_tail = (int)queue == static_priority_end; - } - /* - * Convert the priority into an enable bit field. Try - * to space the bits out evenly so the packet don't - * get grouped up - */ - switch ((int)priority[queue]) { - case 0: - config.s.qos_mask = 0x00; - break; - case 1: - config.s.qos_mask = 0x01; - break; - case 2: - config.s.qos_mask = 0x11; - break; - case 3: - config.s.qos_mask = 0x49; - break; - case 4: - config.s.qos_mask = 0x55; - break; - case 5: - config.s.qos_mask = 0x57; - break; - case 6: - config.s.qos_mask = 0x77; - break; - case 7: - config.s.qos_mask = 0x7f; - break; - case 8: - config.s.qos_mask = 0xff; - break; - case CVMX_PKO_QUEUE_STATIC_PRIORITY: - /* Pass 1 will fall through to the error case */ - if (!cvmx_octeon_is_pass1()) { - config.s.qos_mask = 0xff; - break; - } - default: - cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid " - "priority %llu\n", - (unsigned long long)priority[queue]); - config.s.qos_mask = 0xff; - result_code = CVMX_PKO_INVALID_PRIORITY; - break; - } - - if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) { - cvmx_cmd_queue_result_t cmd_res = - cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO - (base_queue + queue), - CVMX_PKO_MAX_QUEUE_DEPTH, - CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - - - CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST - * 8); - if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) { - switch (cmd_res) { - case CVMX_CMD_QUEUE_NO_MEMORY: - cvmx_dprintf("ERROR: " - "cvmx_pko_config_port: " - "Unable to allocate " - "output buffer.\n"); - return CVMX_PKO_NO_MEMORY; - case CVMX_CMD_QUEUE_ALREADY_SETUP: - cvmx_dprintf - ("ERROR: cvmx_pko_config_port: Port already setup.\n"); - return CVMX_PKO_PORT_ALREADY_SETUP; - case CVMX_CMD_QUEUE_INVALID_PARAM: - default: - cvmx_dprintf - ("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n"); - return CVMX_PKO_CMD_QUEUE_INIT_ERROR; - } - } - - buf_ptr = - (uint64_t *) - cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO - (base_queue + queue)); - config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr); - } else - config.s.buf_ptr = 0; - - CVMX_SYNCWS; - - if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) - cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64); - cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64); - } - - return result_code; -} - -#ifdef PKO_DEBUG -/** - * Show map of ports -> queues for different cores. - */ -void cvmx_pko_show_queue_map() -{ - int core, port; - int pko_output_ports = 36; - - cvmx_dprintf("port"); - for (port = 0; port < pko_output_ports; port++) - cvmx_dprintf("%3d ", port); - cvmx_dprintf("\n"); - - for (core = 0; core < CVMX_MAX_CORES; core++) { - cvmx_dprintf("\n%2d: ", core); - for (port = 0; port < pko_output_ports; port++) { - cvmx_dprintf("%3d ", - cvmx_pko_get_base_queue_per_core(port, - core)); - } - } - cvmx_dprintf("\n"); -} -#endif - -/** - * Rate limit a PKO port to a max packets/sec. This function is only - * supported on CN51XX and higher, excluding CN58XX. - * - * @port: Port to rate limit - * @packets_s: Maximum packet/sec - * @burst: Maximum number of packets to burst in a row before rate - * limiting cuts in. - * - * Returns Zero on success, negative on failure - */ -int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst) -{ - union cvmx_pko_mem_port_rate0 pko_mem_port_rate0; - union cvmx_pko_mem_port_rate1 pko_mem_port_rate1; - - pko_mem_port_rate0.u64 = 0; - pko_mem_port_rate0.s.pid = port; - pko_mem_port_rate0.s.rate_pkt = - cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16; - /* No cost per word since we are limited by packets/sec, not bits/sec */ - pko_mem_port_rate0.s.rate_word = 0; - - pko_mem_port_rate1.u64 = 0; - pko_mem_port_rate1.s.pid = port; - pko_mem_port_rate1.s.rate_lim = - ((uint64_t) pko_mem_port_rate0.s.rate_pkt * burst) >> 8; - - cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); - cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); - return 0; -} - -/** - * Rate limit a PKO port to a max bits/sec. This function is only - * supported on CN51XX and higher, excluding CN58XX. - * - * @port: Port to rate limit - * @bits_s: PKO rate limit in bits/sec - * @burst: Maximum number of bits to burst before rate - * limiting cuts in. - * - * Returns Zero on success, negative on failure - */ -int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) -{ - union cvmx_pko_mem_port_rate0 pko_mem_port_rate0; - union cvmx_pko_mem_port_rate1 pko_mem_port_rate1; - uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz; - uint64_t tokens_per_bit = clock_rate * 16 / bits_s; - - pko_mem_port_rate0.u64 = 0; - pko_mem_port_rate0.s.pid = port; - /* - * Each packet has a 12 bytes of interframe gap, an 8 byte - * preamble, and a 4 byte CRC. These are not included in the - * per word count. Multiply by 8 to covert to bits and divide - * by 256 for limit granularity. - */ - pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; - /* Each 8 byte word has 64bits */ - pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit; - - pko_mem_port_rate1.u64 = 0; - pko_mem_port_rate1.s.pid = port; - pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256; - - cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64); - cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64); - return 0; -} diff --git a/drivers/staging/octeon/cvmx-pko.h b/drivers/staging/octeon/cvmx-pko.h deleted file mode 100644 index de3412aada5d..000000000000 --- a/drivers/staging/octeon/cvmx-pko.h +++ /dev/null @@ -1,610 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * Interface to the hardware Packet Output unit. - * - * Starting with SDK 1.7.0, the PKO output functions now support - * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to - * function similarly to previous SDKs by using POW atomic tags - * to preserve ordering and exclusivity. As a new option, you - * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc - * memory based locking instead. This locking has the advantage - * of not affecting the tag state but doesn't preserve packet - * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most - * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used - * with hand tuned fast path code. - * - * Some of other SDK differences visible to the command command - * queuing: - * - PKO indexes are no longer stored in the FAU. A large - * percentage of the FAU register block used to be tied up - * maintaining PKO queue pointers. These are now stored in a - * global named block. - * - The PKO <b>use_locking</b> parameter can now have a global - * effect. Since all application use the same named block, - * queue locking correctly applies across all operating - * systems when using CVMX_PKO_LOCK_CMD_QUEUE. - * - PKO 3 word commands are now supported. Use - * cvmx_pko_send_packet_finish3(). - * - */ - -#ifndef __CVMX_PKO_H__ -#define __CVMX_PKO_H__ - -#include "cvmx-fpa.h" -#include "cvmx-pow.h" -#include "cvmx-cmd-queue.h" -#include "cvmx-pko-defs.h" - -/* Adjust the command buffer size by 1 word so that in the case of using only - * two word PKO commands no command words stradle buffers. The useful values - * for this are 0 and 1. */ -#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1) - -#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256 -#define CVMX_PKO_MAX_OUTPUT_QUEUES ((OCTEON_IS_MODEL(OCTEON_CN31XX) || \ - OCTEON_IS_MODEL(OCTEON_CN3010) || OCTEON_IS_MODEL(OCTEON_CN3005) || \ - OCTEON_IS_MODEL(OCTEON_CN50XX)) ? 32 : \ - (OCTEON_IS_MODEL(OCTEON_CN58XX) || \ - OCTEON_IS_MODEL(OCTEON_CN56XX)) ? 256 : 128) -#define CVMX_PKO_NUM_OUTPUT_PORTS 40 -/* use this for queues that are not used */ -#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 -#define CVMX_PKO_QUEUE_STATIC_PRIORITY 9 -#define CVMX_PKO_ILLEGAL_QUEUE 0xFFFF -#define CVMX_PKO_MAX_QUEUE_DEPTH 0 - -typedef enum { - CVMX_PKO_SUCCESS, - CVMX_PKO_INVALID_PORT, - CVMX_PKO_INVALID_QUEUE, - CVMX_PKO_INVALID_PRIORITY, - CVMX_PKO_NO_MEMORY, - CVMX_PKO_PORT_ALREADY_SETUP, - CVMX_PKO_CMD_QUEUE_INIT_ERROR -} cvmx_pko_status_t; - -/** - * This enumeration represents the differnet locking modes supported by PKO. - */ -typedef enum { - /* - * PKO doesn't do any locking. It is the responsibility of the - * application to make sure that no other core is accessing - * the same queue at the same time - */ - CVMX_PKO_LOCK_NONE = 0, - /* - * PKO performs an atomic tagswitch to insure exclusive access - * to the output queue. This will maintain packet ordering on - * output. - */ - CVMX_PKO_LOCK_ATOMIC_TAG = 1, - /* - * PKO uses the common command queue locks to insure exclusive - * access to the output queue. This is a memory based - * ll/sc. This is the most portable locking mechanism. - */ - CVMX_PKO_LOCK_CMD_QUEUE = 2, -} cvmx_pko_lock_t; - -typedef struct { - uint32_t packets; - uint64_t octets; - uint64_t doorbell; -} cvmx_pko_port_status_t; - -/** - * This structure defines the address to use on a packet enqueue - */ -typedef union { - uint64_t u64; - struct { - /* Must CVMX_IO_SEG */ - uint64_t mem_space:2; - /* Must be zero */ - uint64_t reserved:13; - /* Must be one */ - uint64_t is_io:1; - /* The ID of the device on the non-coherent bus */ - uint64_t did:8; - /* Must be zero */ - uint64_t reserved2:4; - /* Must be zero */ - uint64_t reserved3:18; - /* - * The hardware likes to have the output port in - * addition to the output queue, - */ - uint64_t port:6; - /* - * The output queue to send the packet to (0-127 are - * legal) - */ - uint64_t queue:9; - /* Must be zero */ - uint64_t reserved4:3; - } s; -} cvmx_pko_doorbell_address_t; - -/** - * Structure of the first packet output command word. - */ -typedef union { - uint64_t u64; - struct { - /* - * The size of the reg1 operation - could be 8, 16, - * 32, or 64 bits. - */ - uint64_t size1:2; - /* - * The size of the reg0 operation - could be 8, 16, - * 32, or 64 bits. - */ - uint64_t size0:2; - /* - * If set, subtract 1, if clear, subtract packet - * size. - */ - uint64_t subone1:1; - /* - * The register, subtract will be done if reg1 is - * non-zero. - */ - uint64_t reg1:11; - /* If set, subtract 1, if clear, subtract packet size */ - uint64_t subone0:1; - /* The register, subtract will be done if reg0 is non-zero */ - uint64_t reg0:11; - /* - * When set, interpret segment pointer and segment - * bytes in little endian order. - */ - uint64_t le:1; - /* - * When set, packet data not allocated in L2 cache by - * PKO. - */ - uint64_t n2:1; - /* - * If set and rsp is set, word3 contains a pointer to - * a work queue entry. - */ - uint64_t wqp:1; - /* If set, the hardware will send a response when done */ - uint64_t rsp:1; - /* - * If set, the supplied pkt_ptr is really a pointer to - * a list of pkt_ptr's. - */ - uint64_t gather:1; - /* - * If ipoffp1 is non zero, (ipoffp1-1) is the number - * of bytes to IP header, and the hardware will - * calculate and insert the UDP/TCP checksum. - */ - uint64_t ipoffp1:7; - /* - * If set, ignore the I bit (force to zero) from all - * pointer structures. - */ - uint64_t ignore_i:1; - /* - * If clear, the hardware will attempt to free the - * buffers containing the packet. - */ - uint64_t dontfree:1; - /* - * The total number of segs in the packet, if gather - * set, also gather list length. - */ - uint64_t segs:6; - /* Including L2, but no trailing CRC */ - uint64_t total_bytes:16; - } s; -} cvmx_pko_command_word0_t; - -/* CSR typedefs have been moved to cvmx-csr-*.h */ - -/** - * Definition of internal state for Packet output processing - */ -typedef struct { - /* ptr to start of buffer, offset kept in FAU reg */ - uint64_t *start_ptr; -} cvmx_pko_state_elem_t; - -/** - * Call before any other calls to initialize the packet - * output system. - */ -extern void cvmx_pko_initialize_global(void); -extern int cvmx_pko_initialize_local(void); - -/** - * Enables the packet output hardware. It must already be - * configured. - */ -extern void cvmx_pko_enable(void); - -/** - * Disables the packet output. Does not affect any configuration. - */ -extern void cvmx_pko_disable(void); - -/** - * Shutdown and free resources required by packet output. - */ - -extern void cvmx_pko_shutdown(void); - -/** - * Configure a output port and the associated queues for use. - * - * @port: Port to configure. - * @base_queue: First queue number to associate with this port. - * @num_queues: Number of queues t oassociate with this port - * @priority: Array of priority levels for each queue. Values are - * allowed to be 1-8. A value of 8 get 8 times the traffic - * of a value of 1. There must be num_queues elements in the - * array. - */ -extern cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, - uint64_t base_queue, - uint64_t num_queues, - const uint64_t priority[]); - -/** - * Ring the packet output doorbell. This tells the packet - * output hardware that "len" command words have been added - * to its pending list. This command includes the required - * CVMX_SYNCWS before the doorbell ring. - * - * @port: Port the packet is for - * @queue: Queue the packet is for - * @len: Length of the command in 64 bit words - */ -static inline void cvmx_pko_doorbell(uint64_t port, uint64_t queue, - uint64_t len) -{ - cvmx_pko_doorbell_address_t ptr; - - ptr.u64 = 0; - ptr.s.mem_space = CVMX_IO_SEG; - ptr.s.did = CVMX_OCT_DID_PKT_SEND; - ptr.s.is_io = 1; - ptr.s.port = port; - ptr.s.queue = queue; - /* - * Need to make sure output queue data is in DRAM before - * doorbell write. - */ - CVMX_SYNCWS; - cvmx_write_io(ptr.u64, len); -} - -/** - * Prepare to send a packet. This may initiate a tag switch to - * get exclusive access to the output queue structure, and - * performs other prep work for the packet send operation. - * - * cvmx_pko_send_packet_finish() MUST be called after this function is called, - * and must be called with the same port/queue/use_locking arguments. - * - * The use_locking parameter allows the caller to use three - * possible locking modes. - * - CVMX_PKO_LOCK_NONE - * - PKO doesn't do any locking. It is the responsibility - * of the application to make sure that no other core - * is accessing the same queue at the same time. - * - CVMX_PKO_LOCK_ATOMIC_TAG - * - PKO performs an atomic tagswitch to insure exclusive - * access to the output queue. This will maintain - * packet ordering on output. - * - CVMX_PKO_LOCK_CMD_QUEUE - * - PKO uses the common command queue locks to insure - * exclusive access to the output queue. This is a - * memory based ll/sc. This is the most portable - * locking mechanism. - * - * NOTE: If atomic locking is used, the POW entry CANNOT be - * descheduled, as it does not contain a valid WQE pointer. - * - * @port: Port to send it on - * @queue: Queue to use - * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or - * CVMX_PKO_LOCK_CMD_QUEUE - */ - -static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue, - cvmx_pko_lock_t use_locking) -{ - if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) { - /* - * Must do a full switch here to handle all cases. We - * use a fake WQE pointer, as the POW does not access - * this memory. The WQE pointer and group are only - * used if this work is descheduled, which is not - * supported by the - * cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish - * combination. Note that this is a special case in - * which these fake values can be used - this is not a - * general technique. - */ - uint32_t tag = - CVMX_TAG_SW_BITS_INTERNAL << CVMX_TAG_SW_SHIFT | - CVMX_TAG_SUBGROUP_PKO << CVMX_TAG_SUBGROUP_SHIFT | - (CVMX_TAG_SUBGROUP_MASK & queue); - cvmx_pow_tag_sw_full((cvmx_wqe_t *) cvmx_phys_to_ptr(0x80), tag, - CVMX_POW_TAG_TYPE_ATOMIC, 0); - } -} - -/** - * Complete packet output. cvmx_pko_send_packet_prepare() must be - * called exactly once before this, and the same parameters must be - * passed to both cvmx_pko_send_packet_prepare() and - * cvmx_pko_send_packet_finish(). - * - * @port: Port to send it on - * @queue: Queue to use - * @pko_command: - * PKO HW command word - * @packet: Packet to send - * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or - * CVMX_PKO_LOCK_CMD_QUEUE - * - * Returns returns CVMX_PKO_SUCCESS on success, or error code on - * failure of output - */ -static inline cvmx_pko_status_t cvmx_pko_send_packet_finish( - uint64_t port, - uint64_t queue, - cvmx_pko_command_word0_t pko_command, - union cvmx_buf_ptr packet, - cvmx_pko_lock_t use_locking) -{ - cvmx_cmd_queue_result_t result; - if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) - cvmx_pow_tag_sw_wait(); - result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), - (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), - pko_command.u64, packet.u64); - if (likely(result == CVMX_CMD_QUEUE_SUCCESS)) { - cvmx_pko_doorbell(port, queue, 2); - return CVMX_PKO_SUCCESS; - } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) - || (result == CVMX_CMD_QUEUE_FULL)) { - return CVMX_PKO_NO_MEMORY; - } else { - return CVMX_PKO_INVALID_QUEUE; - } -} - -/** - * Complete packet output. cvmx_pko_send_packet_prepare() must be - * called exactly once before this, and the same parameters must be - * passed to both cvmx_pko_send_packet_prepare() and - * cvmx_pko_send_packet_finish(). - * - * @port: Port to send it on - * @queue: Queue to use - * @pko_command: - * PKO HW command word - * @packet: Packet to send - * @addr: Plysical address of a work queue entry or physical address - * to zero on complete. - * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or - * CVMX_PKO_LOCK_CMD_QUEUE - * - * Returns returns CVMX_PKO_SUCCESS on success, or error code on - * failure of output - */ -static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3( - uint64_t port, - uint64_t queue, - cvmx_pko_command_word0_t pko_command, - union cvmx_buf_ptr packet, - uint64_t addr, - cvmx_pko_lock_t use_locking) -{ - cvmx_cmd_queue_result_t result; - if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) - cvmx_pow_tag_sw_wait(); - result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), - (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), - pko_command.u64, packet.u64, addr); - if (likely(result == CVMX_CMD_QUEUE_SUCCESS)) { - cvmx_pko_doorbell(port, queue, 3); - return CVMX_PKO_SUCCESS; - } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) - || (result == CVMX_CMD_QUEUE_FULL)) { - return CVMX_PKO_NO_MEMORY; - } else { - return CVMX_PKO_INVALID_QUEUE; - } -} - -/** - * Return the pko output queue associated with a port and a specific core. - * In normal mode (PKO lockless operation is disabled), the value returned - * is the base queue. - * - * @port: Port number - * @core: Core to get queue for - * - * Returns Core-specific output queue - */ -static inline int cvmx_pko_get_base_queue_per_core(int port, int core) -{ -#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 -#define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 16 -#endif -#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 -#define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 16 -#endif - - if (port < CVMX_PKO_MAX_PORTS_INTERFACE0) - return port * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + core; - else if (port >= 16 && port < 16 + CVMX_PKO_MAX_PORTS_INTERFACE1) - return CVMX_PKO_MAX_PORTS_INTERFACE0 * - CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + (port - - 16) * - CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + core; - else if ((port >= 32) && (port < 36)) - return CVMX_PKO_MAX_PORTS_INTERFACE0 * - CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + - CVMX_PKO_MAX_PORTS_INTERFACE1 * - CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + (port - - 32) * - CVMX_PKO_QUEUES_PER_PORT_PCI; - else if ((port >= 36) && (port < 40)) - return CVMX_PKO_MAX_PORTS_INTERFACE0 * - CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + - CVMX_PKO_MAX_PORTS_INTERFACE1 * - CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + - 4 * CVMX_PKO_QUEUES_PER_PORT_PCI + (port - - 36) * - CVMX_PKO_QUEUES_PER_PORT_LOOP; - else - /* Given the limit on the number of ports we can map to - * CVMX_MAX_OUTPUT_QUEUES_STATIC queues (currently 256, - * divided among all cores), the remaining unmapped ports - * are assigned an illegal queue number */ - return CVMX_PKO_ILLEGAL_QUEUE; -} - -/** - * For a given port number, return the base pko output queue - * for the port. - * - * @port: Port number - * Returns Base output queue - */ -static inline int cvmx_pko_get_base_queue(int port) -{ - return cvmx_pko_get_base_queue_per_core(port, 0); -} - -/** - * For a given port number, return the number of pko output queues. - * - * @port: Port number - * Returns Number of output queues - */ -static inline int cvmx_pko_get_num_queues(int port) -{ - if (port < 16) - return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0; - else if (port < 32) - return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1; - else if (port < 36) - return CVMX_PKO_QUEUES_PER_PORT_PCI; - else if (port < 40) - return CVMX_PKO_QUEUES_PER_PORT_LOOP; - else - return 0; -} - -/** - * Get the status counters for a port. - * - * @port_num: Port number to get statistics for. - * @clear: Set to 1 to clear the counters after they are read - * @status: Where to put the results. - */ -static inline void cvmx_pko_get_port_status(uint64_t port_num, uint64_t clear, - cvmx_pko_port_status_t *status) -{ - union cvmx_pko_reg_read_idx pko_reg_read_idx; - union cvmx_pko_mem_count0 pko_mem_count0; - union cvmx_pko_mem_count1 pko_mem_count1; - - pko_reg_read_idx.u64 = 0; - pko_reg_read_idx.s.index = port_num; - cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); - - pko_mem_count0.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT0); - status->packets = pko_mem_count0.s.count; - if (clear) { - pko_mem_count0.s.count = port_num; - cvmx_write_csr(CVMX_PKO_MEM_COUNT0, pko_mem_count0.u64); - } - - pko_mem_count1.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT1); - status->octets = pko_mem_count1.s.count; - if (clear) { - pko_mem_count1.s.count = port_num; - cvmx_write_csr(CVMX_PKO_MEM_COUNT1, pko_mem_count1.u64); - } - - if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { - union cvmx_pko_mem_debug9 debug9; - pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num); - cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); - debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9); - status->doorbell = debug9.cn38xx.doorbell; - } else { - union cvmx_pko_mem_debug8 debug8; - pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num); - cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); - debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8); - status->doorbell = debug8.cn58xx.doorbell; - } -} - -/** - * Rate limit a PKO port to a max packets/sec. This function is only - * supported on CN57XX, CN56XX, CN55XX, and CN54XX. - * - * @port: Port to rate limit - * @packets_s: Maximum packet/sec - * @burst: Maximum number of packets to burst in a row before rate - * limiting cuts in. - * - * Returns Zero on success, negative on failure - */ -extern int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst); - -/** - * Rate limit a PKO port to a max bits/sec. This function is only - * supported on CN57XX, CN56XX, CN55XX, and CN54XX. - * - * @port: Port to rate limit - * @bits_s: PKO rate limit in bits/sec - * @burst: Maximum number of bits to burst before rate - * limiting cuts in. - * - * Returns Zero on success, negative on failure - */ -extern int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst); - -#endif /* __CVMX_PKO_H__ */ diff --git a/drivers/staging/octeon/cvmx-pow.h b/drivers/staging/octeon/cvmx-pow.h deleted file mode 100644 index 999aefe3274c..000000000000 --- a/drivers/staging/octeon/cvmx-pow.h +++ /dev/null @@ -1,1982 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * Interface to the hardware Packet Order / Work unit. - * - * New, starting with SDK 1.7.0, cvmx-pow supports a number of - * extended consistency checks. The define - * CVMX_ENABLE_POW_CHECKS controls the runtime insertion of POW - * internal state checks to find common programming errors. If - * CVMX_ENABLE_POW_CHECKS is not defined, checks are by default - * enabled. For example, cvmx-pow will check for the following - * program errors or POW state inconsistency. - * - Requesting a POW operation with an active tag switch in - * progress. - * - Waiting for a tag switch to complete for an excessively - * long period. This is normally a sign of an error in locking - * causing deadlock. - * - Illegal tag switches from NULL_NULL. - * - Illegal tag switches from NULL. - * - Illegal deschedule request. - * - WQE pointer not matching the one attached to the core by - * the POW. - * - */ - -#ifndef __CVMX_POW_H__ -#define __CVMX_POW_H__ - -#include <asm/octeon/cvmx-pow-defs.h> - -#include "cvmx-scratch.h" -#include "cvmx-wqe.h" - -/* Default to having all POW constancy checks turned on */ -#ifndef CVMX_ENABLE_POW_CHECKS -#define CVMX_ENABLE_POW_CHECKS 1 -#endif - -enum cvmx_pow_tag_type { - /* Tag ordering is maintained */ - CVMX_POW_TAG_TYPE_ORDERED = 0L, - /* Tag ordering is maintained, and at most one PP has the tag */ - CVMX_POW_TAG_TYPE_ATOMIC = 1L, - /* - * The work queue entry from the order - NEVER tag switch from - * NULL to NULL - */ - CVMX_POW_TAG_TYPE_NULL = 2L, - /* A tag switch to NULL, and there is no space reserved in POW - * - NEVER tag switch to NULL_NULL - * - NEVER tag switch from NULL_NULL - * - NULL_NULL is entered at the beginning of time and on a deschedule. - * - NULL_NULL can be exited by a new work request. A NULL_SWITCH - * load can also switch the state to NULL - */ - CVMX_POW_TAG_TYPE_NULL_NULL = 3L -}; - -/** - * Wait flag values for pow functions. - */ -typedef enum { - CVMX_POW_WAIT = 1, - CVMX_POW_NO_WAIT = 0, -} cvmx_pow_wait_t; - -/** - * POW tag operations. These are used in the data stored to the POW. - */ -typedef enum { - /* - * switch the tag (only) for this PP - * - the previous tag should be non-NULL in this case - * - tag switch response required - * - fields used: op, type, tag - */ - CVMX_POW_TAG_OP_SWTAG = 0L, - /* - * switch the tag for this PP, with full information - * - this should be used when the previous tag is NULL - * - tag switch response required - * - fields used: address, op, grp, type, tag - */ - CVMX_POW_TAG_OP_SWTAG_FULL = 1L, - /* - * switch the tag (and/or group) for this PP and de-schedule - * - OK to keep the tag the same and only change the group - * - fields used: op, no_sched, grp, type, tag - */ - CVMX_POW_TAG_OP_SWTAG_DESCH = 2L, - /* - * just de-schedule - * - fields used: op, no_sched - */ - CVMX_POW_TAG_OP_DESCH = 3L, - /* - * create an entirely new work queue entry - * - fields used: address, op, qos, grp, type, tag - */ - CVMX_POW_TAG_OP_ADDWQ = 4L, - /* - * just update the work queue pointer and grp for this PP - * - fields used: address, op, grp - */ - CVMX_POW_TAG_OP_UPDATE_WQP_GRP = 5L, - /* - * set the no_sched bit on the de-schedule list - * - * - does nothing if the selected entry is not on the - * de-schedule list - * - * - does nothing if the stored work queue pointer does not - * match the address field - * - * - fields used: address, index, op - * - * Before issuing a *_NSCHED operation, SW must guarantee - * that all prior deschedules and set/clr NSCHED operations - * are complete and all prior switches are complete. The - * hardware provides the opsdone bit and swdone bit for SW - * polling. After issuing a *_NSCHED operation, SW must - * guarantee that the set/clr NSCHED is complete before any - * subsequent operations. - */ - CVMX_POW_TAG_OP_SET_NSCHED = 6L, - /* - * clears the no_sched bit on the de-schedule list - * - * - does nothing if the selected entry is not on the - * de-schedule list - * - * - does nothing if the stored work queue pointer does not - * match the address field - * - * - fields used: address, index, op - * - * Before issuing a *_NSCHED operation, SW must guarantee that - * all prior deschedules and set/clr NSCHED operations are - * complete and all prior switches are complete. The hardware - * provides the opsdone bit and swdone bit for SW - * polling. After issuing a *_NSCHED operation, SW must - * guarantee that the set/clr NSCHED is complete before any - * subsequent operations. - */ - CVMX_POW_TAG_OP_CLR_NSCHED = 7L, - /* do nothing */ - CVMX_POW_TAG_OP_NOP = 15L -} cvmx_pow_tag_op_t; - -/** - * This structure defines the store data on a store to POW - */ -typedef union { - uint64_t u64; - struct { - /* - * Don't reschedule this entry. no_sched is used for - * CVMX_POW_TAG_OP_SWTAG_DESCH and - * CVMX_POW_TAG_OP_DESCH - */ - uint64_t no_sched:1; - uint64_t unused:2; - /* Tontains index of entry for a CVMX_POW_TAG_OP_*_NSCHED */ - uint64_t index:13; - /* The operation to perform */ - cvmx_pow_tag_op_t op:4; - uint64_t unused2:2; - /* - * The QOS level for the packet. qos is only used for - * CVMX_POW_TAG_OP_ADDWQ - */ - uint64_t qos:3; - /* - * The group that the work queue entry will be - * scheduled to grp is used for CVMX_POW_TAG_OP_ADDWQ, - * CVMX_POW_TAG_OP_SWTAG_FULL, - * CVMX_POW_TAG_OP_SWTAG_DESCH, and - * CVMX_POW_TAG_OP_UPDATE_WQP_GRP - */ - uint64_t grp:4; - /* - * The type of the tag. type is used for everything - * except CVMX_POW_TAG_OP_DESCH, - * CVMX_POW_TAG_OP_UPDATE_WQP_GRP, and - * CVMX_POW_TAG_OP_*_NSCHED - */ - uint64_t type:3; - /* - * The actual tag. tag is used for everything except - * CVMX_POW_TAG_OP_DESCH, - * CVMX_POW_TAG_OP_UPDATE_WQP_GRP, and - * CVMX_POW_TAG_OP_*_NSCHED - */ - uint64_t tag:32; - } s; -} cvmx_pow_tag_req_t; - -/** - * This structure describes the address to load stuff from POW - */ -typedef union { - uint64_t u64; - - /** - * Address for new work request loads (did<2:0> == 0) - */ - struct { - /* Mips64 address region. Should be CVMX_IO_SEG */ - uint64_t mem_region:2; - /* Must be zero */ - uint64_t reserved_49_61:13; - /* Must be one */ - uint64_t is_io:1; - /* the ID of POW -- did<2:0> == 0 in this case */ - uint64_t did:8; - /* Must be zero */ - uint64_t reserved_4_39:36; - /* - * If set, don't return load response until work is - * available. - */ - uint64_t wait:1; - /* Must be zero */ - uint64_t reserved_0_2:3; - } swork; - - /** - * Address for loads to get POW internal status - */ - struct { - /* Mips64 address region. Should be CVMX_IO_SEG */ - uint64_t mem_region:2; - /* Must be zero */ - uint64_t reserved_49_61:13; - /* Must be one */ - uint64_t is_io:1; - /* the ID of POW -- did<2:0> == 1 in this case */ - uint64_t did:8; - /* Must be zero */ - uint64_t reserved_10_39:30; - /* The core id to get status for */ - uint64_t coreid:4; - /* - * If set and get_cur is set, return reverse tag-list - * pointer rather than forward tag-list pointer. - */ - uint64_t get_rev:1; - /* - * If set, return current status rather than pending - * status. - */ - uint64_t get_cur:1; - /* - * If set, get the work-queue pointer rather than - * tag/type. - */ - uint64_t get_wqp:1; - /* Must be zero */ - uint64_t reserved_0_2:3; - } sstatus; - - /** - * Address for memory loads to get POW internal state - */ - struct { - /* Mips64 address region. Should be CVMX_IO_SEG */ - uint64_t mem_region:2; - /* Must be zero */ - uint64_t reserved_49_61:13; - /* Must be one */ - uint64_t is_io:1; - /* the ID of POW -- did<2:0> == 2 in this case */ - uint64_t did:8; - /* Must be zero */ - uint64_t reserved_16_39:24; - /* POW memory index */ - uint64_t index:11; - /* - * If set, return deschedule information rather than - * the standard response for work-queue index (invalid - * if the work-queue entry is not on the deschedule - * list). - */ - uint64_t get_des:1; - /* - * If set, get the work-queue pointer rather than - * tag/type (no effect when get_des set). - */ - uint64_t get_wqp:1; - /* Must be zero */ - uint64_t reserved_0_2:3; - } smemload; - - /** - * Address for index/pointer loads - */ - struct { - /* Mips64 address region. Should be CVMX_IO_SEG */ - uint64_t mem_region:2; - /* Must be zero */ - uint64_t reserved_49_61:13; - /* Must be one */ - uint64_t is_io:1; - /* the ID of POW -- did<2:0> == 3 in this case */ - uint64_t did:8; - /* Must be zero */ - uint64_t reserved_9_39:31; - /* - * when {get_rmt ==0 AND get_des_get_tail == 0}, this - * field selects one of eight POW internal-input - * queues (0-7), one per QOS level; values 8-15 are - * illegal in this case; when {get_rmt ==0 AND - * get_des_get_tail == 1}, this field selects one of - * 16 deschedule lists (per group); when get_rmt ==1, - * this field selects one of 16 memory-input queue - * lists. The two memory-input queue lists associated - * with each QOS level are: - * - * - qosgrp = 0, qosgrp = 8: QOS0 - * - qosgrp = 1, qosgrp = 9: QOS1 - * - qosgrp = 2, qosgrp = 10: QOS2 - * - qosgrp = 3, qosgrp = 11: QOS3 - * - qosgrp = 4, qosgrp = 12: QOS4 - * - qosgrp = 5, qosgrp = 13: QOS5 - * - qosgrp = 6, qosgrp = 14: QOS6 - * - qosgrp = 7, qosgrp = 15: QOS7 - */ - uint64_t qosgrp:4; - /* - * If set and get_rmt is clear, return deschedule list - * indexes rather than indexes for the specified qos - * level; if set and get_rmt is set, return the tail - * pointer rather than the head pointer for the - * specified qos level. - */ - uint64_t get_des_get_tail:1; - /* - * If set, return remote pointers rather than the - * local indexes for the specified qos level. - */ - uint64_t get_rmt:1; - /* Must be zero */ - uint64_t reserved_0_2:3; - } sindexload; - - /** - * address for NULL_RD request (did<2:0> == 4) when this is read, - * HW attempts to change the state to NULL if it is NULL_NULL (the - * hardware cannot switch from NULL_NULL to NULL if a POW entry is - * not available - software may need to recover by finishing - * another piece of work before a POW entry can ever become - * available.) - */ - struct { - /* Mips64 address region. Should be CVMX_IO_SEG */ - uint64_t mem_region:2; - /* Must be zero */ - uint64_t reserved_49_61:13; - /* Must be one */ - uint64_t is_io:1; - /* the ID of POW -- did<2:0> == 4 in this case */ - uint64_t did:8; - /* Must be zero */ - uint64_t reserved_0_39:40; - } snull_rd; -} cvmx_pow_load_addr_t; - -/** - * This structure defines the response to a load/SENDSINGLE to POW - * (except CSR reads) - */ -typedef union { - uint64_t u64; - - /** - * Response to new work request loads - */ - struct { - /* - * Set when no new work queue entry was returned. * - * If there was de-scheduled work, the HW will - * definitely return it. When this bit is set, it - * could mean either mean: - * - * - There was no work, or - * - * - There was no work that the HW could find. This - * case can happen, regardless of the wait bit value - * in the original request, when there is work in - * the IQ's that is too deep down the list. - */ - uint64_t no_work:1; - /* Must be zero */ - uint64_t reserved_40_62:23; - /* 36 in O1 -- the work queue pointer */ - uint64_t addr:40; - } s_work; - - /** - * Result for a POW Status Load (when get_cur==0 and get_wqp==0) - */ - struct { - uint64_t reserved_62_63:2; - /* Set when there is a pending non-NULL SWTAG or - * SWTAG_FULL, and the POW entry has not left the list - * for the original tag. */ - uint64_t pend_switch:1; - /* Set when SWTAG_FULL and pend_switch is set. */ - uint64_t pend_switch_full:1; - /* - * Set when there is a pending NULL SWTAG, or an - * implicit switch to NULL. - */ - uint64_t pend_switch_null:1; - /* Set when there is a pending DESCHED or SWTAG_DESCHED. */ - uint64_t pend_desched:1; - /* - * Set when there is a pending SWTAG_DESCHED and - * pend_desched is set. - */ - uint64_t pend_desched_switch:1; - /* Set when nosched is desired and pend_desched is set. */ - uint64_t pend_nosched:1; - /* Set when there is a pending GET_WORK. */ - uint64_t pend_new_work:1; - /* - * When pend_new_work is set, this bit indicates that - * the wait bit was set. - */ - uint64_t pend_new_work_wait:1; - /* Set when there is a pending NULL_RD. */ - uint64_t pend_null_rd:1; - /* Set when there is a pending CLR_NSCHED. */ - uint64_t pend_nosched_clr:1; - uint64_t reserved_51:1; - /* This is the index when pend_nosched_clr is set. */ - uint64_t pend_index:11; - /* - * This is the new_grp when (pend_desched AND - * pend_desched_switch) is set. - */ - uint64_t pend_grp:4; - uint64_t reserved_34_35:2; - /* - * This is the tag type when pend_switch or - * (pend_desched AND pend_desched_switch) are set. - */ - uint64_t pend_type:2; - /* - * - this is the tag when pend_switch or (pend_desched - * AND pend_desched_switch) are set. - */ - uint64_t pend_tag:32; - } s_sstatus0; - - /** - * Result for a POW Status Load (when get_cur==0 and get_wqp==1) - */ - struct { - uint64_t reserved_62_63:2; - /* - * Set when there is a pending non-NULL SWTAG or - * SWTAG_FULL, and the POW entry has not left the list - * for the original tag. - */ - uint64_t pend_switch:1; - /* Set when SWTAG_FULL and pend_switch is set. */ - uint64_t pend_switch_full:1; - /* - * Set when there is a pending NULL SWTAG, or an - * implicit switch to NULL. - */ - uint64_t pend_switch_null:1; - /* - * Set when there is a pending DESCHED or - * SWTAG_DESCHED. - */ - uint64_t pend_desched:1; - /* - * Set when there is a pending SWTAG_DESCHED and - * pend_desched is set. - */ - uint64_t pend_desched_switch:1; - /* Set when nosched is desired and pend_desched is set. */ - uint64_t pend_nosched:1; - /* Set when there is a pending GET_WORK. */ - uint64_t pend_new_work:1; - /* - * When pend_new_work is set, this bit indicates that - * the wait bit was set. - */ - uint64_t pend_new_work_wait:1; - /* Set when there is a pending NULL_RD. */ - uint64_t pend_null_rd:1; - /* Set when there is a pending CLR_NSCHED. */ - uint64_t pend_nosched_clr:1; - uint64_t reserved_51:1; - /* This is the index when pend_nosched_clr is set. */ - uint64_t pend_index:11; - /* - * This is the new_grp when (pend_desched AND - * pend_desched_switch) is set. - */ - uint64_t pend_grp:4; - /* This is the wqp when pend_nosched_clr is set. */ - uint64_t pend_wqp:36; - } s_sstatus1; - - /** - * Result for a POW Status Load (when get_cur==1, get_wqp==0, and - * get_rev==0) - */ - struct { - uint64_t reserved_62_63:2; - /* - * Points to the next POW entry in the tag list when - * tail == 0 (and tag_type is not NULL or NULL_NULL). - */ - uint64_t link_index:11; - /* The POW entry attached to the core. */ - uint64_t index:11; - /* - * The group attached to the core (updated when new - * tag list entered on SWTAG_FULL). - */ - uint64_t grp:4; - /* - * Set when this POW entry is at the head of its tag - * list (also set when in the NULL or NULL_NULL - * state). - */ - uint64_t head:1; - /* - * Set when this POW entry is at the tail of its tag - * list (also set when in the NULL or NULL_NULL - * state). - */ - uint64_t tail:1; - /* - * The tag type attached to the core (updated when new - * tag list entered on SWTAG, SWTAG_FULL, or - * SWTAG_DESCHED). - */ - uint64_t tag_type:2; - /* - * The tag attached to the core (updated when new tag - * list entered on SWTAG, SWTAG_FULL, or - * SWTAG_DESCHED). - */ - uint64_t tag:32; - } s_sstatus2; - - /** - * Result for a POW Status Load (when get_cur==1, get_wqp==0, and get_rev==1) - */ - struct { - uint64_t reserved_62_63:2; - /* - * Points to the prior POW entry in the tag list when - * head == 0 (and tag_type is not NULL or - * NULL_NULL). This field is unpredictable when the - * core's state is NULL or NULL_NULL. - */ - uint64_t revlink_index:11; - /* The POW entry attached to the core. */ - uint64_t index:11; - /* - * The group attached to the core (updated when new - * tag list entered on SWTAG_FULL). - */ - uint64_t grp:4; - /* Set when this POW entry is at the head of its tag - * list (also set when in the NULL or NULL_NULL - * state). - */ - uint64_t head:1; - /* - * Set when this POW entry is at the tail of its tag - * list (also set when in the NULL or NULL_NULL - * state). - */ - uint64_t tail:1; - /* - * The tag type attached to the core (updated when new - * tag list entered on SWTAG, SWTAG_FULL, or - * SWTAG_DESCHED). - */ - uint64_t tag_type:2; - /* - * The tag attached to the core (updated when new tag - * list entered on SWTAG, SWTAG_FULL, or - * SWTAG_DESCHED). - */ - uint64_t tag:32; - } s_sstatus3; - - /** - * Result for a POW Status Load (when get_cur==1, get_wqp==1, and - * get_rev==0) - */ - struct { - uint64_t reserved_62_63:2; - /* - * Points to the next POW entry in the tag list when - * tail == 0 (and tag_type is not NULL or NULL_NULL). - */ - uint64_t link_index:11; - /* The POW entry attached to the core. */ - uint64_t index:11; - /* - * The group attached to the core (updated when new - * tag list entered on SWTAG_FULL). - */ - uint64_t grp:4; - /* - * The wqp attached to the core (updated when new tag - * list entered on SWTAG_FULL). - */ - uint64_t wqp:36; - } s_sstatus4; - - /** - * Result for a POW Status Load (when get_cur==1, get_wqp==1, and - * get_rev==1) - */ - struct { - uint64_t reserved_62_63:2; - /* - * Points to the prior POW entry in the tag list when - * head == 0 (and tag_type is not NULL or - * NULL_NULL). This field is unpredictable when the - * core's state is NULL or NULL_NULL. - */ - uint64_t revlink_index:11; - /* The POW entry attached to the core. */ - uint64_t index:11; - /* - * The group attached to the core (updated when new - * tag list entered on SWTAG_FULL). - */ - uint64_t grp:4; - /* - * The wqp attached to the core (updated when new tag - * list entered on SWTAG_FULL). - */ - uint64_t wqp:36; - } s_sstatus5; - - /** - * Result For POW Memory Load (get_des == 0 and get_wqp == 0) - */ - struct { - uint64_t reserved_51_63:13; - /* - * The next entry in the input, free, descheduled_head - * list (unpredictable if entry is the tail of the - * list). - */ - uint64_t next_index:11; - /* The group of the POW entry. */ - uint64_t grp:4; - uint64_t reserved_35:1; - /* - * Set when this POW entry is at the tail of its tag - * list (also set when in the NULL or NULL_NULL - * state). - */ - uint64_t tail:1; - /* The tag type of the POW entry. */ - uint64_t tag_type:2; - /* The tag of the POW entry. */ - uint64_t tag:32; - } s_smemload0; - - /** - * Result For POW Memory Load (get_des == 0 and get_wqp == 1) - */ - struct { - uint64_t reserved_51_63:13; - /* - * The next entry in the input, free, descheduled_head - * list (unpredictable if entry is the tail of the - * list). - */ - uint64_t next_index:11; - /* The group of the POW entry. */ - uint64_t grp:4; - /* The WQP held in the POW entry. */ - uint64_t wqp:36; - } s_smemload1; - - /** - * Result For POW Memory Load (get_des == 1) - */ - struct { - uint64_t reserved_51_63:13; - /* - * The next entry in the tag list connected to the - * descheduled head. - */ - uint64_t fwd_index:11; - /* The group of the POW entry. */ - uint64_t grp:4; - /* The nosched bit for the POW entry. */ - uint64_t nosched:1; - /* There is a pending tag switch */ - uint64_t pend_switch:1; - /* - * The next tag type for the new tag list when - * pend_switch is set. - */ - uint64_t pend_type:2; - /* - * The next tag for the new tag list when pend_switch - * is set. - */ - uint64_t pend_tag:32; - } s_smemload2; - - /** - * Result For POW Index/Pointer Load (get_rmt == 0/get_des_get_tail == 0) - */ - struct { - uint64_t reserved_52_63:12; - /* - * set when there is one or more POW entries on the - * free list. - */ - uint64_t free_val:1; - /* - * set when there is exactly one POW entry on the free - * list. - */ - uint64_t free_one:1; - uint64_t reserved_49:1; - /* - * when free_val is set, indicates the first entry on - * the free list. - */ - uint64_t free_head:11; - uint64_t reserved_37:1; - /* - * when free_val is set, indicates the last entry on - * the free list. - */ - uint64_t free_tail:11; - /* - * set when there is one or more POW entries on the - * input Q list selected by qosgrp. - */ - uint64_t loc_val:1; - /* - * set when there is exactly one POW entry on the - * input Q list selected by qosgrp. - */ - uint64_t loc_one:1; - uint64_t reserved_23:1; - /* - * when loc_val is set, indicates the first entry on - * the input Q list selected by qosgrp. - */ - uint64_t loc_head:11; - uint64_t reserved_11:1; - /* - * when loc_val is set, indicates the last entry on - * the input Q list selected by qosgrp. - */ - uint64_t loc_tail:11; - } sindexload0; - - /** - * Result For POW Index/Pointer Load (get_rmt == 0/get_des_get_tail == 1) - */ - struct { - uint64_t reserved_52_63:12; - /* - * set when there is one or more POW entries on the - * nosched list. - */ - uint64_t nosched_val:1; - /* - * set when there is exactly one POW entry on the - * nosched list. - */ - uint64_t nosched_one:1; - uint64_t reserved_49:1; - /* - * when nosched_val is set, indicates the first entry - * on the nosched list. - */ - uint64_t nosched_head:11; - uint64_t reserved_37:1; - /* - * when nosched_val is set, indicates the last entry - * on the nosched list. - */ - uint64_t nosched_tail:11; - /* - * set when there is one or more descheduled heads on - * the descheduled list selected by qosgrp. - */ - uint64_t des_val:1; - /* - * set when there is exactly one descheduled head on - * the descheduled list selected by qosgrp. - */ - uint64_t des_one:1; - uint64_t reserved_23:1; - /* - * when des_val is set, indicates the first - * descheduled head on the descheduled list selected - * by qosgrp. - */ - uint64_t des_head:11; - uint64_t reserved_11:1; - /* - * when des_val is set, indicates the last descheduled - * head on the descheduled list selected by qosgrp. - */ - uint64_t des_tail:11; - } sindexload1; - - /** - * Result For POW Index/Pointer Load (get_rmt == 1/get_des_get_tail == 0) - */ - struct { - uint64_t reserved_39_63:25; - /* - * Set when this DRAM list is the current head - * (i.e. is the next to be reloaded when the POW - * hardware reloads a POW entry from DRAM). The POW - * hardware alternates between the two DRAM lists - * associated with a QOS level when it reloads work - * from DRAM into the POW unit. - */ - uint64_t rmt_is_head:1; - /* - * Set when the DRAM portion of the input Q list - * selected by qosgrp contains one or more pieces of - * work. - */ - uint64_t rmt_val:1; - /* - * Set when the DRAM portion of the input Q list - * selected by qosgrp contains exactly one piece of - * work. - */ - uint64_t rmt_one:1; - /* - * When rmt_val is set, indicates the first piece of - * work on the DRAM input Q list selected by - * qosgrp. - */ - uint64_t rmt_head:36; - } sindexload2; - - /** - * Result For POW Index/Pointer Load (get_rmt == - * 1/get_des_get_tail == 1) - */ - struct { - uint64_t reserved_39_63:25; - /* - * set when this DRAM list is the current head - * (i.e. is the next to be reloaded when the POW - * hardware reloads a POW entry from DRAM). The POW - * hardware alternates between the two DRAM lists - * associated with a QOS level when it reloads work - * from DRAM into the POW unit. - */ - uint64_t rmt_is_head:1; - /* - * set when the DRAM portion of the input Q list - * selected by qosgrp contains one or more pieces of - * work. - */ - uint64_t rmt_val:1; - /* - * set when the DRAM portion of the input Q list - * selected by qosgrp contains exactly one piece of - * work. - */ - uint64_t rmt_one:1; - /* - * when rmt_val is set, indicates the last piece of - * work on the DRAM input Q list selected by - * qosgrp. - */ - uint64_t rmt_tail:36; - } sindexload3; - - /** - * Response to NULL_RD request loads - */ - struct { - uint64_t unused:62; - /* of type cvmx_pow_tag_type_t. state is one of the - * following: - * - * - CVMX_POW_TAG_TYPE_ORDERED - * - CVMX_POW_TAG_TYPE_ATOMIC - * - CVMX_POW_TAG_TYPE_NULL - * - CVMX_POW_TAG_TYPE_NULL_NULL - */ - uint64_t state:2; - } s_null_rd; - -} cvmx_pow_tag_load_resp_t; - -/** - * This structure describes the address used for stores to the POW. - * The store address is meaningful on stores to the POW. The - * hardware assumes that an aligned 64-bit store was used for all - * these stores. Note the assumption that the work queue entry is - * aligned on an 8-byte boundary (since the low-order 3 address bits - * must be zero). Note that not all fields are used by all - * operations. - * - * NOTE: The following is the behavior of the pending switch bit at the PP - * for POW stores (i.e. when did<7:3> == 0xc) - * - did<2:0> == 0 => pending switch bit is set - * - did<2:0> == 1 => no affect on the pending switch bit - * - did<2:0> == 3 => pending switch bit is cleared - * - did<2:0> == 7 => no affect on the pending switch bit - * - did<2:0> == others => must not be used - * - No other loads/stores have an affect on the pending switch bit - * - The switch bus from POW can clear the pending switch bit - * - * NOTE: did<2:0> == 2 is used by the HW for a special single-cycle - * ADDWQ command that only contains the pointer). SW must never use - * did<2:0> == 2. - */ -typedef union { - /** - * Unsigned 64 bit integer representation of store address - */ - uint64_t u64; - - struct { - /* Memory region. Should be CVMX_IO_SEG in most cases */ - uint64_t mem_reg:2; - uint64_t reserved_49_61:13; /* Must be zero */ - uint64_t is_io:1; /* Must be one */ - /* Device ID of POW. Note that different sub-dids are used. */ - uint64_t did:8; - uint64_t reserved_36_39:4; /* Must be zero */ - /* Address field. addr<2:0> must be zero */ - uint64_t addr:36; - } stag; -} cvmx_pow_tag_store_addr_t; - -/** - * decode of the store data when an IOBDMA SENDSINGLE is sent to POW - */ -typedef union { - uint64_t u64; - - struct { - /* - * the (64-bit word) location in scratchpad to write - * to (if len != 0) - */ - uint64_t scraddr:8; - /* the number of words in the response (0 => no response) */ - uint64_t len:8; - /* the ID of the device on the non-coherent bus */ - uint64_t did:8; - uint64_t unused:36; - /* if set, don't return load response until work is available */ - uint64_t wait:1; - uint64_t unused2:3; - } s; - -} cvmx_pow_iobdma_store_t; - -/* CSR typedefs have been moved to cvmx-csr-*.h */ - -/** - * Get the POW tag for this core. This returns the current - * tag type, tag, group, and POW entry index associated with - * this core. Index is only valid if the tag type isn't NULL_NULL. - * If a tag switch is pending this routine returns the tag before - * the tag switch, not after. - * - * Returns Current tag - */ -static inline cvmx_pow_tag_req_t cvmx_pow_get_current_tag(void) -{ - cvmx_pow_load_addr_t load_addr; - cvmx_pow_tag_load_resp_t load_resp; - cvmx_pow_tag_req_t result; - - load_addr.u64 = 0; - load_addr.sstatus.mem_region = CVMX_IO_SEG; - load_addr.sstatus.is_io = 1; - load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; - load_addr.sstatus.coreid = cvmx_get_core_num(); - load_addr.sstatus.get_cur = 1; - load_resp.u64 = cvmx_read_csr(load_addr.u64); - result.u64 = 0; - result.s.grp = load_resp.s_sstatus2.grp; - result.s.index = load_resp.s_sstatus2.index; - result.s.type = load_resp.s_sstatus2.tag_type; - result.s.tag = load_resp.s_sstatus2.tag; - return result; -} - -/** - * Get the POW WQE for this core. This returns the work queue - * entry currently associated with this core. - * - * Returns WQE pointer - */ -static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void) -{ - cvmx_pow_load_addr_t load_addr; - cvmx_pow_tag_load_resp_t load_resp; - - load_addr.u64 = 0; - load_addr.sstatus.mem_region = CVMX_IO_SEG; - load_addr.sstatus.is_io = 1; - load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1; - load_addr.sstatus.coreid = cvmx_get_core_num(); - load_addr.sstatus.get_cur = 1; - load_addr.sstatus.get_wqp = 1; - load_resp.u64 = cvmx_read_csr(load_addr.u64); - return (cvmx_wqe_t *) cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp); -} - -#ifndef CVMX_MF_CHORD -#define CVMX_MF_CHORD(dest) CVMX_RDHWR(dest, 30) -#endif - -/** - * Print a warning if a tag switch is pending for this core - * - * @function: Function name checking for a pending tag switch - */ -static inline void __cvmx_pow_warn_if_pending_switch(const char *function) -{ - uint64_t switch_complete; - CVMX_MF_CHORD(switch_complete); - if (!switch_complete) - pr_warning("%s called with tag switch in progress\n", function); -} - -/** - * Waits for a tag switch to complete by polling the completion bit. - * Note that switches to NULL complete immediately and do not need - * to be waited for. - */ -static inline void cvmx_pow_tag_sw_wait(void) -{ - const uint64_t MAX_CYCLES = 1ull << 31; - uint64_t switch_complete; - uint64_t start_cycle = cvmx_get_cycle(); - while (1) { - CVMX_MF_CHORD(switch_complete); - if (unlikely(switch_complete)) - break; - if (unlikely(cvmx_get_cycle() > start_cycle + MAX_CYCLES)) { - pr_warning("Tag switch is taking a long time, " - "possible deadlock\n"); - start_cycle = -MAX_CYCLES - 1; - } - } -} - -/** - * Synchronous work request. Requests work from the POW. - * This function does NOT wait for previous tag switches to complete, - * so the caller must ensure that there is not a pending tag switch. - * - * @wait: When set, call stalls until work becomes avaiable, or times out. - * If not set, returns immediately. - * - * Returns Returns the WQE pointer from POW. Returns NULL if no work - * was available. - */ -static inline cvmx_wqe_t *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t - wait) -{ - cvmx_pow_load_addr_t ptr; - cvmx_pow_tag_load_resp_t result; - - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - ptr.u64 = 0; - ptr.swork.mem_region = CVMX_IO_SEG; - ptr.swork.is_io = 1; - ptr.swork.did = CVMX_OCT_DID_TAG_SWTAG; - ptr.swork.wait = wait; - - result.u64 = cvmx_read_csr(ptr.u64); - - if (result.s_work.no_work) - return NULL; - else - return (cvmx_wqe_t *) cvmx_phys_to_ptr(result.s_work.addr); -} - -/** - * Synchronous work request. Requests work from the POW. - * This function waits for any previous tag switch to complete before - * requesting the new work. - * - * @wait: When set, call stalls until work becomes avaiable, or times out. - * If not set, returns immediately. - * - * Returns Returns the WQE pointer from POW. Returns NULL if no work - * was available. - */ -static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait) -{ - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* Must not have a switch pending when requesting work */ - cvmx_pow_tag_sw_wait(); - return cvmx_pow_work_request_sync_nocheck(wait); - -} - -/** - * Synchronous null_rd request. Requests a switch out of NULL_NULL POW state. - * This function waits for any previous tag switch to complete before - * requesting the null_rd. - * - * Returns Returns the POW state of type cvmx_pow_tag_type_t. - */ -static inline enum cvmx_pow_tag_type cvmx_pow_work_request_null_rd(void) -{ - cvmx_pow_load_addr_t ptr; - cvmx_pow_tag_load_resp_t result; - - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* Must not have a switch pending when requesting work */ - cvmx_pow_tag_sw_wait(); - - ptr.u64 = 0; - ptr.snull_rd.mem_region = CVMX_IO_SEG; - ptr.snull_rd.is_io = 1; - ptr.snull_rd.did = CVMX_OCT_DID_TAG_NULL_RD; - - result.u64 = cvmx_read_csr(ptr.u64); - - return (enum cvmx_pow_tag_type) result.s_null_rd.state; -} - -/** - * Asynchronous work request. Work is requested from the POW unit, - * and should later be checked with function - * cvmx_pow_work_response_async. This function does NOT wait for - * previous tag switches to complete, so the caller must ensure that - * there is not a pending tag switch. - * - * @scr_addr: Scratch memory address that response will be returned - * to, which is either a valid WQE, or a response with the - * invalid bit set. Byte address, must be 8 byte aligned. - * - * @wait: 1 to cause response to wait for work to become available (or - * timeout), 0 to cause response to return immediately - */ -static inline void cvmx_pow_work_request_async_nocheck(int scr_addr, - cvmx_pow_wait_t wait) -{ - cvmx_pow_iobdma_store_t data; - - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* scr_addr must be 8 byte aligned */ - data.s.scraddr = scr_addr >> 3; - data.s.len = 1; - data.s.did = CVMX_OCT_DID_TAG_SWTAG; - data.s.wait = wait; - cvmx_send_single(data.u64); -} - -/** - * Asynchronous work request. Work is requested from the POW unit, - * and should later be checked with function - * cvmx_pow_work_response_async. This function waits for any previous - * tag switch to complete before requesting the new work. - * - * @scr_addr: Scratch memory address that response will be returned - * to, which is either a valid WQE, or a response with the - * invalid bit set. Byte address, must be 8 byte aligned. - * - * @wait: 1 to cause response to wait for work to become available (or - * timeout), 0 to cause response to return immediately - */ -static inline void cvmx_pow_work_request_async(int scr_addr, - cvmx_pow_wait_t wait) -{ - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* Must not have a switch pending when requesting work */ - cvmx_pow_tag_sw_wait(); - cvmx_pow_work_request_async_nocheck(scr_addr, wait); -} - -/** - * Gets result of asynchronous work request. Performs a IOBDMA sync - * to wait for the response. - * - * @scr_addr: Scratch memory address to get result from Byte address, - * must be 8 byte aligned. - * - * Returns Returns the WQE from the scratch register, or NULL if no - * work was available. - */ -static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr) -{ - cvmx_pow_tag_load_resp_t result; - - CVMX_SYNCIOBDMA; - result.u64 = cvmx_scratch_read64(scr_addr); - - if (result.s_work.no_work) - return NULL; - else - return (cvmx_wqe_t *) cvmx_phys_to_ptr(result.s_work.addr); -} - -/** - * Checks if a work queue entry pointer returned by a work - * request is valid. It may be invalid due to no work - * being available or due to a timeout. - * - * @wqe_ptr: pointer to a work queue entry returned by the POW - * - * Returns 0 if pointer is valid - * 1 if invalid (no work was returned) - */ -static inline uint64_t cvmx_pow_work_invalid(cvmx_wqe_t *wqe_ptr) -{ - return wqe_ptr == NULL; -} - -/** - * Starts a tag switch to the provided tag value and tag type. - * Completion for the tag switch must be checked for separately. This - * function does NOT update the work queue entry in dram to match tag - * value and type, so the application must keep track of these if they - * are important to the application. This tag switch command must not - * be used for switches to NULL, as the tag switch pending bit will be - * set by the switch request, but never cleared by the hardware. - * - * NOTE: This should not be used when switching from a NULL tag. Use - * cvmx_pow_tag_sw_full() instead. - * - * This function does no checks, so the caller must ensure that any - * previous tag switch has completed. - * - * @tag: new tag value - * @tag_type: new tag type (ordered or atomic) - */ -static inline void cvmx_pow_tag_sw_nocheck(uint32_t tag, - enum cvmx_pow_tag_type tag_type) -{ - cvmx_addr_t ptr; - cvmx_pow_tag_req_t tag_req; - - if (CVMX_ENABLE_POW_CHECKS) { - cvmx_pow_tag_req_t current_tag; - __cvmx_pow_warn_if_pending_switch(__func__); - current_tag = cvmx_pow_get_current_tag(); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called with NULL tag\n", __func__); - if ((current_tag.s.type == tag_type) - && (current_tag.s.tag == tag)) - pr_warning("%s called to perform a tag switch to the " - "same tag\n", - __func__); - if (tag_type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called to perform a tag switch to " - "NULL. Use cvmx_pow_tag_sw_null() instead\n", - __func__); - } - - /* - * Note that WQE in DRAM is not updated here, as the POW does - * not read from DRAM once the WQE is in flight. See hardware - * manual for complete details. It is the application's - * responsibility to keep track of the current tag value if - * that is important. - */ - - tag_req.u64 = 0; - tag_req.s.op = CVMX_POW_TAG_OP_SWTAG; - tag_req.s.tag = tag; - tag_req.s.type = tag_type; - - ptr.u64 = 0; - ptr.sio.mem_region = CVMX_IO_SEG; - ptr.sio.is_io = 1; - ptr.sio.did = CVMX_OCT_DID_TAG_SWTAG; - - /* once this store arrives at POW, it will attempt the switch - software must wait for the switch to complete separately */ - cvmx_write_io(ptr.u64, tag_req.u64); -} - -/** - * Starts a tag switch to the provided tag value and tag type. - * Completion for the tag switch must be checked for separately. This - * function does NOT update the work queue entry in dram to match tag - * value and type, so the application must keep track of these if they - * are important to the application. This tag switch command must not - * be used for switches to NULL, as the tag switch pending bit will be - * set by the switch request, but never cleared by the hardware. - * - * NOTE: This should not be used when switching from a NULL tag. Use - * cvmx_pow_tag_sw_full() instead. - * - * This function waits for any previous tag switch to complete, and also - * displays an error on tag switches to NULL. - * - * @tag: new tag value - * @tag_type: new tag type (ordered or atomic) - */ -static inline void cvmx_pow_tag_sw(uint32_t tag, - enum cvmx_pow_tag_type tag_type) -{ - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* - * Note that WQE in DRAM is not updated here, as the POW does - * not read from DRAM once the WQE is in flight. See hardware - * manual for complete details. It is the application's - * responsibility to keep track of the current tag value if - * that is important. - */ - - /* - * Ensure that there is not a pending tag switch, as a tag - * switch cannot be started if a previous switch is still - * pending. - */ - cvmx_pow_tag_sw_wait(); - cvmx_pow_tag_sw_nocheck(tag, tag_type); -} - -/** - * Starts a tag switch to the provided tag value and tag type. - * Completion for the tag switch must be checked for separately. This - * function does NOT update the work queue entry in dram to match tag - * value and type, so the application must keep track of these if they - * are important to the application. This tag switch command must not - * be used for switches to NULL, as the tag switch pending bit will be - * set by the switch request, but never cleared by the hardware. - * - * This function must be used for tag switches from NULL. - * - * This function does no checks, so the caller must ensure that any - * previous tag switch has completed. - * - * @wqp: pointer to work queue entry to submit. This entry is - * updated to match the other parameters - * @tag: tag value to be assigned to work queue entry - * @tag_type: type of tag - * @group: group value for the work queue entry. - */ -static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, uint32_t tag, - enum cvmx_pow_tag_type tag_type, - uint64_t group) -{ - cvmx_addr_t ptr; - cvmx_pow_tag_req_t tag_req; - - if (CVMX_ENABLE_POW_CHECKS) { - cvmx_pow_tag_req_t current_tag; - __cvmx_pow_warn_if_pending_switch(__func__); - current_tag = cvmx_pow_get_current_tag(); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); - if ((current_tag.s.type == tag_type) - && (current_tag.s.tag == tag)) - pr_warning("%s called to perform a tag switch to " - "the same tag\n", - __func__); - if (tag_type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called to perform a tag switch to " - "NULL. Use cvmx_pow_tag_sw_null() instead\n", - __func__); - if (wqp != cvmx_phys_to_ptr(0x80)) - if (wqp != cvmx_pow_get_current_wqp()) - pr_warning("%s passed WQE(%p) doesn't match " - "the address in the POW(%p)\n", - __func__, wqp, - cvmx_pow_get_current_wqp()); - } - - /* - * Note that WQE in DRAM is not updated here, as the POW does - * not read from DRAM once the WQE is in flight. See hardware - * manual for complete details. It is the application's - * responsibility to keep track of the current tag value if - * that is important. - */ - - tag_req.u64 = 0; - tag_req.s.op = CVMX_POW_TAG_OP_SWTAG_FULL; - tag_req.s.tag = tag; - tag_req.s.type = tag_type; - tag_req.s.grp = group; - - ptr.u64 = 0; - ptr.sio.mem_region = CVMX_IO_SEG; - ptr.sio.is_io = 1; - ptr.sio.did = CVMX_OCT_DID_TAG_SWTAG; - ptr.sio.offset = CAST64(wqp); - - /* - * once this store arrives at POW, it will attempt the switch - * software must wait for the switch to complete separately. - */ - cvmx_write_io(ptr.u64, tag_req.u64); -} - -/** - * Starts a tag switch to the provided tag value and tag type. - * Completion for the tag switch must be checked for separately. This - * function does NOT update the work queue entry in dram to match tag - * value and type, so the application must keep track of these if they - * are important to the application. This tag switch command must not - * be used for switches to NULL, as the tag switch pending bit will be - * set by the switch request, but never cleared by the hardware. - * - * This function must be used for tag switches from NULL. - * - * This function waits for any pending tag switches to complete - * before requesting the tag switch. - * - * @wqp: pointer to work queue entry to submit. This entry is updated - * to match the other parameters - * @tag: tag value to be assigned to work queue entry - * @tag_type: type of tag - * @group: group value for the work queue entry. - */ -static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, uint32_t tag, - enum cvmx_pow_tag_type tag_type, - uint64_t group) -{ - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* - * Ensure that there is not a pending tag switch, as a tag - * switch cannot be started if a previous switch is still - * pending. - */ - cvmx_pow_tag_sw_wait(); - cvmx_pow_tag_sw_full_nocheck(wqp, tag, tag_type, group); -} - -/** - * Switch to a NULL tag, which ends any ordering or - * synchronization provided by the POW for the current - * work queue entry. This operation completes immediately, - * so completion should not be waited for. - * This function does NOT wait for previous tag switches to complete, - * so the caller must ensure that any previous tag switches have completed. - */ -static inline void cvmx_pow_tag_sw_null_nocheck(void) -{ - cvmx_addr_t ptr; - cvmx_pow_tag_req_t tag_req; - - if (CVMX_ENABLE_POW_CHECKS) { - cvmx_pow_tag_req_t current_tag; - __cvmx_pow_warn_if_pending_switch(__func__); - current_tag = cvmx_pow_get_current_tag(); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called when we already have a " - "NULL tag\n", - __func__); - } - - tag_req.u64 = 0; - tag_req.s.op = CVMX_POW_TAG_OP_SWTAG; - tag_req.s.type = CVMX_POW_TAG_TYPE_NULL; - - ptr.u64 = 0; - ptr.sio.mem_region = CVMX_IO_SEG; - ptr.sio.is_io = 1; - ptr.sio.did = CVMX_OCT_DID_TAG_TAG1; - - cvmx_write_io(ptr.u64, tag_req.u64); - - /* switch to NULL completes immediately */ -} - -/** - * Switch to a NULL tag, which ends any ordering or - * synchronization provided by the POW for the current - * work queue entry. This operation completes immediately, - * so completion should not be waited for. - * This function waits for any pending tag switches to complete - * before requesting the switch to NULL. - */ -static inline void cvmx_pow_tag_sw_null(void) -{ - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* - * Ensure that there is not a pending tag switch, as a tag - * switch cannot be started if a previous switch is still - * pending. - */ - cvmx_pow_tag_sw_wait(); - cvmx_pow_tag_sw_null_nocheck(); - - /* switch to NULL completes immediately */ -} - -/** - * Submits work to an input queue. This function updates the work - * queue entry in DRAM to match the arguments given. Note that the - * tag provided is for the work queue entry submitted, and is - * unrelated to the tag that the core currently holds. - * - * @wqp: pointer to work queue entry to submit. This entry is - * updated to match the other parameters - * @tag: tag value to be assigned to work queue entry - * @tag_type: type of tag - * @qos: Input queue to add to. - * @grp: group value for the work queue entry. - */ -static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, - enum cvmx_pow_tag_type tag_type, - uint64_t qos, uint64_t grp) -{ - cvmx_addr_t ptr; - cvmx_pow_tag_req_t tag_req; - - wqp->qos = qos; - wqp->tag = tag; - wqp->tag_type = tag_type; - wqp->grp = grp; - - tag_req.u64 = 0; - tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; - tag_req.s.type = tag_type; - tag_req.s.tag = tag; - tag_req.s.qos = qos; - tag_req.s.grp = grp; - - ptr.u64 = 0; - ptr.sio.mem_region = CVMX_IO_SEG; - ptr.sio.is_io = 1; - ptr.sio.did = CVMX_OCT_DID_TAG_TAG1; - ptr.sio.offset = cvmx_ptr_to_phys(wqp); - - /* - * SYNC write to memory before the work submit. This is - * necessary as POW may read values from DRAM at this time. - */ - CVMX_SYNCWS; - cvmx_write_io(ptr.u64, tag_req.u64); -} - -/** - * This function sets the group mask for a core. The group mask - * indicates which groups each core will accept work from. There are - * 16 groups. - * - * @core_num: core to apply mask to - * @mask: Group mask. There are 16 groups, so only bits 0-15 are valid, - * representing groups 0-15. - * Each 1 bit in the mask enables the core to accept work from - * the corresponding group. - */ -static inline void cvmx_pow_set_group_mask(uint64_t core_num, uint64_t mask) -{ - union cvmx_pow_pp_grp_mskx grp_msk; - - grp_msk.u64 = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(core_num)); - grp_msk.s.grp_msk = mask; - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); -} - -/** - * This function sets POW static priorities for a core. Each input queue has - * an associated priority value. - * - * @core_num: core to apply priorities to - * @priority: Vector of 8 priorities, one per POW Input Queue (0-7). - * Highest priority is 0 and lowest is 7. A priority value - * of 0xF instructs POW to skip the Input Queue when - * scheduling to this specific core. - * NOTE: priorities should not have gaps in values, meaning - * {0,1,1,1,1,1,1,1} is a valid configuration while - * {0,2,2,2,2,2,2,2} is not. - */ -static inline void cvmx_pow_set_priority(uint64_t core_num, - const uint8_t priority[]) -{ - /* POW priorities are supported on CN5xxx and later */ - if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) { - union cvmx_pow_pp_grp_mskx grp_msk; - - grp_msk.u64 = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(core_num)); - grp_msk.s.qos0_pri = priority[0]; - grp_msk.s.qos1_pri = priority[1]; - grp_msk.s.qos2_pri = priority[2]; - grp_msk.s.qos3_pri = priority[3]; - grp_msk.s.qos4_pri = priority[4]; - grp_msk.s.qos5_pri = priority[5]; - grp_msk.s.qos6_pri = priority[6]; - grp_msk.s.qos7_pri = priority[7]; - - /* Detect gaps between priorities and flag error */ - { - int i; - uint32_t prio_mask = 0; - - for (i = 0; i < 8; i++) - if (priority[i] != 0xF) - prio_mask |= 1 << priority[i]; - - if (prio_mask ^ ((1 << cvmx_pop(prio_mask)) - 1)) { - pr_err("POW static priorities should be " - "contiguous (0x%llx)\n", - (unsigned long long)prio_mask); - return; - } - } - - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(core_num), grp_msk.u64); - } -} - -/** - * Performs a tag switch and then an immediate deschedule. This completes - * immediately, so completion must not be waited for. This function does NOT - * update the wqe in DRAM to match arguments. - * - * This function does NOT wait for any prior tag switches to complete, so the - * calling code must do this. - * - * Note the following CAVEAT of the Octeon HW behavior when - * re-scheduling DE-SCHEDULEd items whose (next) state is - * ORDERED: - * - If there are no switches pending at the time that the - * HW executes the de-schedule, the HW will only re-schedule - * the head of the FIFO associated with the given tag. This - * means that in many respects, the HW treats this ORDERED - * tag as an ATOMIC tag. Note that in the SWTAG_DESCH - * case (to an ORDERED tag), the HW will do the switch - * before the deschedule whenever it is possible to do - * the switch immediately, so it may often look like - * this case. - * - If there is a pending switch to ORDERED at the time - * the HW executes the de-schedule, the HW will perform - * the switch at the time it re-schedules, and will be - * able to reschedule any/all of the entries with the - * same tag. - * Due to this behavior, the RECOMMENDATION to software is - * that they have a (next) state of ATOMIC when they - * DE-SCHEDULE. If an ORDERED tag is what was really desired, - * SW can choose to immediately switch to an ORDERED tag - * after the work (that has an ATOMIC tag) is re-scheduled. - * Note that since there are never any tag switches pending - * when the HW re-schedules, this switch can be IMMEDIATE upon - * the reception of the pointer during the re-schedule. - * - * @tag: New tag value - * @tag_type: New tag type - * @group: New group value - * @no_sched: Control whether this work queue entry will be rescheduled. - * - 1 : don't schedule this work - * - 0 : allow this work to be scheduled. - */ -static inline void cvmx_pow_tag_sw_desched_nocheck( - uint32_t tag, - enum cvmx_pow_tag_type tag_type, - uint64_t group, - uint64_t no_sched) -{ - cvmx_addr_t ptr; - cvmx_pow_tag_req_t tag_req; - - if (CVMX_ENABLE_POW_CHECKS) { - cvmx_pow_tag_req_t current_tag; - __cvmx_pow_warn_if_pending_switch(__func__); - current_tag = cvmx_pow_get_current_tag(); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called with NULL tag. Deschedule not " - "allowed from NULL state\n", - __func__); - if ((current_tag.s.type != CVMX_POW_TAG_TYPE_ATOMIC) - && (tag_type != CVMX_POW_TAG_TYPE_ATOMIC)) - pr_warning("%s called where neither the before or " - "after tag is ATOMIC\n", - __func__); - } - - tag_req.u64 = 0; - tag_req.s.op = CVMX_POW_TAG_OP_SWTAG_DESCH; - tag_req.s.tag = tag; - tag_req.s.type = tag_type; - tag_req.s.grp = group; - tag_req.s.no_sched = no_sched; - - ptr.u64 = 0; - ptr.sio.mem_region = CVMX_IO_SEG; - ptr.sio.is_io = 1; - ptr.sio.did = CVMX_OCT_DID_TAG_TAG3; - /* - * since TAG3 is used, this store will clear the local pending - * switch bit. - */ - cvmx_write_io(ptr.u64, tag_req.u64); -} - -/** - * Performs a tag switch and then an immediate deschedule. This completes - * immediately, so completion must not be waited for. This function does NOT - * update the wqe in DRAM to match arguments. - * - * This function waits for any prior tag switches to complete, so the - * calling code may call this function with a pending tag switch. - * - * Note the following CAVEAT of the Octeon HW behavior when - * re-scheduling DE-SCHEDULEd items whose (next) state is - * ORDERED: - * - If there are no switches pending at the time that the - * HW executes the de-schedule, the HW will only re-schedule - * the head of the FIFO associated with the given tag. This - * means that in many respects, the HW treats this ORDERED - * tag as an ATOMIC tag. Note that in the SWTAG_DESCH - * case (to an ORDERED tag), the HW will do the switch - * before the deschedule whenever it is possible to do - * the switch immediately, so it may often look like - * this case. - * - If there is a pending switch to ORDERED at the time - * the HW executes the de-schedule, the HW will perform - * the switch at the time it re-schedules, and will be - * able to reschedule any/all of the entries with the - * same tag. - * Due to this behavior, the RECOMMENDATION to software is - * that they have a (next) state of ATOMIC when they - * DE-SCHEDULE. If an ORDERED tag is what was really desired, - * SW can choose to immediately switch to an ORDERED tag - * after the work (that has an ATOMIC tag) is re-scheduled. - * Note that since there are never any tag switches pending - * when the HW re-schedules, this switch can be IMMEDIATE upon - * the reception of the pointer during the re-schedule. - * - * @tag: New tag value - * @tag_type: New tag type - * @group: New group value - * @no_sched: Control whether this work queue entry will be rescheduled. - * - 1 : don't schedule this work - * - 0 : allow this work to be scheduled. - */ -static inline void cvmx_pow_tag_sw_desched(uint32_t tag, - enum cvmx_pow_tag_type tag_type, - uint64_t group, uint64_t no_sched) -{ - if (CVMX_ENABLE_POW_CHECKS) - __cvmx_pow_warn_if_pending_switch(__func__); - - /* Need to make sure any writes to the work queue entry are complete */ - CVMX_SYNCWS; - /* - * Ensure that there is not a pending tag switch, as a tag - * switch cannot be started if a previous switch is still - * pending. - */ - cvmx_pow_tag_sw_wait(); - cvmx_pow_tag_sw_desched_nocheck(tag, tag_type, group, no_sched); -} - -/** - * Descchedules the current work queue entry. - * - * @no_sched: no schedule flag value to be set on the work queue - * entry. If this is set the entry will not be - * rescheduled. - */ -static inline void cvmx_pow_desched(uint64_t no_sched) -{ - cvmx_addr_t ptr; - cvmx_pow_tag_req_t tag_req; - - if (CVMX_ENABLE_POW_CHECKS) { - cvmx_pow_tag_req_t current_tag; - __cvmx_pow_warn_if_pending_switch(__func__); - current_tag = cvmx_pow_get_current_tag(); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL_NULL) - pr_warning("%s called with NULL_NULL tag\n", - __func__); - if (current_tag.s.type == CVMX_POW_TAG_TYPE_NULL) - pr_warning("%s called with NULL tag. Deschedule not " - "expected from NULL state\n", - __func__); - } - - /* Need to make sure any writes to the work queue entry are complete */ - CVMX_SYNCWS; - - tag_req.u64 = 0; - tag_req.s.op = CVMX_POW_TAG_OP_DESCH; - tag_req.s.no_sched = no_sched; - - ptr.u64 = 0; - ptr.sio.mem_region = CVMX_IO_SEG; - ptr.sio.is_io = 1; - ptr.sio.did = CVMX_OCT_DID_TAG_TAG3; - /* - * since TAG3 is used, this store will clear the local pending - * switch bit. - */ - cvmx_write_io(ptr.u64, tag_req.u64); -} - -/**************************************************** -* Define usage of bits within the 32 bit tag values. -*****************************************************/ - -/* - * Number of bits of the tag used by software. The SW bits are always - * a contiguous block of the high starting at bit 31. The hardware - * bits are always the low bits. By default, the top 8 bits of the - * tag are reserved for software, and the low 24 are set by the IPD - * unit. - */ -#define CVMX_TAG_SW_BITS (8) -#define CVMX_TAG_SW_SHIFT (32 - CVMX_TAG_SW_BITS) - -/* Below is the list of values for the top 8 bits of the tag. */ -/* - * Tag values with top byte of this value are reserved for internal - * executive uses. - */ -#define CVMX_TAG_SW_BITS_INTERNAL 0x1 -/* The executive divides the remaining 24 bits as follows: - * - the upper 8 bits (bits 23 - 16 of the tag) define a subgroup - * - * - the lower 16 bits (bits 15 - 0 of the tag) define are the value - * with the subgroup - * - * Note that this section describes the format of tags generated by - * software - refer to the hardware documentation for a description of - * the tags values generated by the packet input hardware. Subgroups - * are defined here. - */ -/* Mask for the value portion of the tag */ -#define CVMX_TAG_SUBGROUP_MASK 0xFFFF -#define CVMX_TAG_SUBGROUP_SHIFT 16 -#define CVMX_TAG_SUBGROUP_PKO 0x1 - -/* End of executive tag subgroup definitions */ - -/* - * The remaining values software bit values 0x2 - 0xff are available - * for application use. - */ - -/** - * This function creates a 32 bit tag value from the two values provided. - * - * @sw_bits: The upper bits (number depends on configuration) are set - * to this value. The remainder of bits are set by the - * hw_bits parameter. - * - * @hw_bits: The lower bits (number depends on configuration) are set - * to this value. The remainder of bits are set by the - * sw_bits parameter. - * - * Returns 32 bit value of the combined hw and sw bits. - */ -static inline uint32_t cvmx_pow_tag_compose(uint64_t sw_bits, uint64_t hw_bits) -{ - return ((sw_bits & cvmx_build_mask(CVMX_TAG_SW_BITS)) << - CVMX_TAG_SW_SHIFT) | - (hw_bits & cvmx_build_mask(32 - CVMX_TAG_SW_BITS)); -} - -/** - * Extracts the bits allocated for software use from the tag - * - * @tag: 32 bit tag value - * - * Returns N bit software tag value, where N is configurable with the - * CVMX_TAG_SW_BITS define - */ -static inline uint32_t cvmx_pow_tag_get_sw_bits(uint64_t tag) -{ - return (tag >> (32 - CVMX_TAG_SW_BITS)) & - cvmx_build_mask(CVMX_TAG_SW_BITS); -} - -/** - * - * Extracts the bits allocated for hardware use from the tag - * - * @tag: 32 bit tag value - * - * Returns (32 - N) bit software tag value, where N is configurable - * with the CVMX_TAG_SW_BITS define - */ -static inline uint32_t cvmx_pow_tag_get_hw_bits(uint64_t tag) -{ - return tag & cvmx_build_mask(32 - CVMX_TAG_SW_BITS); -} - -/** - * Store the current POW internal state into the supplied - * buffer. It is recommended that you pass a buffer of at least - * 128KB. The format of the capture may change based on SDK - * version and Octeon chip. - * - * @buffer: Buffer to store capture into - * @buffer_size: - * The size of the supplied buffer - * - * Returns Zero on success, negative on failure - */ -extern int cvmx_pow_capture(void *buffer, int buffer_size); - -/** - * Dump a POW capture to the console in a human readable format. - * - * @buffer: POW capture from cvmx_pow_capture() - * @buffer_size: - * Size of the buffer - */ -extern void cvmx_pow_display(void *buffer, int buffer_size); - -/** - * Return the number of POW entries supported by this chip - * - * Returns Number of POW entries - */ -extern int cvmx_pow_get_num_entries(void); - -#endif /* __CVMX_POW_H__ */ diff --git a/drivers/staging/octeon/cvmx-scratch.h b/drivers/staging/octeon/cvmx-scratch.h deleted file mode 100644 index 96b70cfd6245..000000000000 --- a/drivers/staging/octeon/cvmx-scratch.h +++ /dev/null @@ -1,139 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * This file provides support for the processor local scratch memory. - * Scratch memory is byte addressable - all addresses are byte addresses. - * - */ - -#ifndef __CVMX_SCRATCH_H__ -#define __CVMX_SCRATCH_H__ - -/* - * Note: This define must be a long, not a long long in order to - * compile without warnings for both 32bit and 64bit. - */ -#define CVMX_SCRATCH_BASE (-32768l) /* 0xffffffffffff8000 */ - -/** - * Reads an 8 bit value from the processor local scratchpad memory. - * - * @address: byte address to read from - * - * Returns value read - */ -static inline uint8_t cvmx_scratch_read8(uint64_t address) -{ - return *CASTPTR(volatile uint8_t, CVMX_SCRATCH_BASE + address); -} - -/** - * Reads a 16 bit value from the processor local scratchpad memory. - * - * @address: byte address to read from - * - * Returns value read - */ -static inline uint16_t cvmx_scratch_read16(uint64_t address) -{ - return *CASTPTR(volatile uint16_t, CVMX_SCRATCH_BASE + address); -} - -/** - * Reads a 32 bit value from the processor local scratchpad memory. - * - * @address: byte address to read from - * - * Returns value read - */ -static inline uint32_t cvmx_scratch_read32(uint64_t address) -{ - return *CASTPTR(volatile uint32_t, CVMX_SCRATCH_BASE + address); -} - -/** - * Reads a 64 bit value from the processor local scratchpad memory. - * - * @address: byte address to read from - * - * Returns value read - */ -static inline uint64_t cvmx_scratch_read64(uint64_t address) -{ - return *CASTPTR(volatile uint64_t, CVMX_SCRATCH_BASE + address); -} - -/** - * Writes an 8 bit value to the processor local scratchpad memory. - * - * @address: byte address to write to - * @value: value to write - */ -static inline void cvmx_scratch_write8(uint64_t address, uint64_t value) -{ - *CASTPTR(volatile uint8_t, CVMX_SCRATCH_BASE + address) = - (uint8_t) value; -} - -/** - * Writes a 32 bit value to the processor local scratchpad memory. - * - * @address: byte address to write to - * @value: value to write - */ -static inline void cvmx_scratch_write16(uint64_t address, uint64_t value) -{ - *CASTPTR(volatile uint16_t, CVMX_SCRATCH_BASE + address) = - (uint16_t) value; -} - -/** - * Writes a 16 bit value to the processor local scratchpad memory. - * - * @address: byte address to write to - * @value: value to write - */ -static inline void cvmx_scratch_write32(uint64_t address, uint64_t value) -{ - *CASTPTR(volatile uint32_t, CVMX_SCRATCH_BASE + address) = - (uint32_t) value; -} - -/** - * Writes a 64 bit value to the processor local scratchpad memory. - * - * @address: byte address to write to - * @value: value to write - */ -static inline void cvmx_scratch_write64(uint64_t address, uint64_t value) -{ - *CASTPTR(volatile uint64_t, CVMX_SCRATCH_BASE + address) = value; -} - -#endif /* __CVMX_SCRATCH_H__ */ diff --git a/drivers/staging/octeon/cvmx-smix-defs.h b/drivers/staging/octeon/cvmx-smix-defs.h deleted file mode 100644 index 9ae45fcbe3e3..000000000000 --- a/drivers/staging/octeon/cvmx-smix-defs.h +++ /dev/null @@ -1,178 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_SMIX_DEFS_H__ -#define __CVMX_SMIX_DEFS_H__ - -#define CVMX_SMIX_CLK(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_CMD(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_EN(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_RD_DAT(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256)) -#define CVMX_SMIX_WR_DAT(offset) \ - CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256)) - -union cvmx_smix_clk { - uint64_t u64; - struct cvmx_smix_clk_s { - uint64_t reserved_25_63:39; - uint64_t mode:1; - uint64_t reserved_21_23:3; - uint64_t sample_hi:5; - uint64_t sample_mode:1; - uint64_t reserved_14_14:1; - uint64_t clk_idle:1; - uint64_t preamble:1; - uint64_t sample:4; - uint64_t phase:8; - } s; - struct cvmx_smix_clk_cn30xx { - uint64_t reserved_21_63:43; - uint64_t sample_hi:5; - uint64_t reserved_14_15:2; - uint64_t clk_idle:1; - uint64_t preamble:1; - uint64_t sample:4; - uint64_t phase:8; - } cn30xx; - struct cvmx_smix_clk_cn30xx cn31xx; - struct cvmx_smix_clk_cn30xx cn38xx; - struct cvmx_smix_clk_cn30xx cn38xxp2; - struct cvmx_smix_clk_cn50xx { - uint64_t reserved_25_63:39; - uint64_t mode:1; - uint64_t reserved_21_23:3; - uint64_t sample_hi:5; - uint64_t reserved_14_15:2; - uint64_t clk_idle:1; - uint64_t preamble:1; - uint64_t sample:4; - uint64_t phase:8; - } cn50xx; - struct cvmx_smix_clk_s cn52xx; - struct cvmx_smix_clk_cn50xx cn52xxp1; - struct cvmx_smix_clk_s cn56xx; - struct cvmx_smix_clk_cn50xx cn56xxp1; - struct cvmx_smix_clk_cn30xx cn58xx; - struct cvmx_smix_clk_cn30xx cn58xxp1; -}; - -union cvmx_smix_cmd { - uint64_t u64; - struct cvmx_smix_cmd_s { - uint64_t reserved_18_63:46; - uint64_t phy_op:2; - uint64_t reserved_13_15:3; - uint64_t phy_adr:5; - uint64_t reserved_5_7:3; - uint64_t reg_adr:5; - } s; - struct cvmx_smix_cmd_cn30xx { - uint64_t reserved_17_63:47; - uint64_t phy_op:1; - uint64_t reserved_13_15:3; - uint64_t phy_adr:5; - uint64_t reserved_5_7:3; - uint64_t reg_adr:5; - } cn30xx; - struct cvmx_smix_cmd_cn30xx cn31xx; - struct cvmx_smix_cmd_cn30xx cn38xx; - struct cvmx_smix_cmd_cn30xx cn38xxp2; - struct cvmx_smix_cmd_s cn50xx; - struct cvmx_smix_cmd_s cn52xx; - struct cvmx_smix_cmd_s cn52xxp1; - struct cvmx_smix_cmd_s cn56xx; - struct cvmx_smix_cmd_s cn56xxp1; - struct cvmx_smix_cmd_cn30xx cn58xx; - struct cvmx_smix_cmd_cn30xx cn58xxp1; -}; - -union cvmx_smix_en { - uint64_t u64; - struct cvmx_smix_en_s { - uint64_t reserved_1_63:63; - uint64_t en:1; - } s; - struct cvmx_smix_en_s cn30xx; - struct cvmx_smix_en_s cn31xx; - struct cvmx_smix_en_s cn38xx; - struct cvmx_smix_en_s cn38xxp2; - struct cvmx_smix_en_s cn50xx; - struct cvmx_smix_en_s cn52xx; - struct cvmx_smix_en_s cn52xxp1; - struct cvmx_smix_en_s cn56xx; - struct cvmx_smix_en_s cn56xxp1; - struct cvmx_smix_en_s cn58xx; - struct cvmx_smix_en_s cn58xxp1; -}; - -union cvmx_smix_rd_dat { - uint64_t u64; - struct cvmx_smix_rd_dat_s { - uint64_t reserved_18_63:46; - uint64_t pending:1; - uint64_t val:1; - uint64_t dat:16; - } s; - struct cvmx_smix_rd_dat_s cn30xx; - struct cvmx_smix_rd_dat_s cn31xx; - struct cvmx_smix_rd_dat_s cn38xx; - struct cvmx_smix_rd_dat_s cn38xxp2; - struct cvmx_smix_rd_dat_s cn50xx; - struct cvmx_smix_rd_dat_s cn52xx; - struct cvmx_smix_rd_dat_s cn52xxp1; - struct cvmx_smix_rd_dat_s cn56xx; - struct cvmx_smix_rd_dat_s cn56xxp1; - struct cvmx_smix_rd_dat_s cn58xx; - struct cvmx_smix_rd_dat_s cn58xxp1; -}; - -union cvmx_smix_wr_dat { - uint64_t u64; - struct cvmx_smix_wr_dat_s { - uint64_t reserved_18_63:46; - uint64_t pending:1; - uint64_t val:1; - uint64_t dat:16; - } s; - struct cvmx_smix_wr_dat_s cn30xx; - struct cvmx_smix_wr_dat_s cn31xx; - struct cvmx_smix_wr_dat_s cn38xx; - struct cvmx_smix_wr_dat_s cn38xxp2; - struct cvmx_smix_wr_dat_s cn50xx; - struct cvmx_smix_wr_dat_s cn52xx; - struct cvmx_smix_wr_dat_s cn52xxp1; - struct cvmx_smix_wr_dat_s cn56xx; - struct cvmx_smix_wr_dat_s cn56xxp1; - struct cvmx_smix_wr_dat_s cn58xx; - struct cvmx_smix_wr_dat_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-spi.c b/drivers/staging/octeon/cvmx-spi.c deleted file mode 100644 index 82794d920cec..000000000000 --- a/drivers/staging/octeon/cvmx-spi.c +++ /dev/null @@ -1,667 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * Support library for the SPI - */ -#include <asm/octeon/octeon.h> - -#include "cvmx-config.h" - -#include "cvmx-pko.h" -#include "cvmx-spi.h" - -#include "cvmx-spxx-defs.h" -#include "cvmx-stxx-defs.h" -#include "cvmx-srxx-defs.h" - -#define INVOKE_CB(function_p, args...) \ - do { \ - if (function_p) { \ - res = function_p(args); \ - if (res) \ - return res; \ - } \ - } while (0) - -#if CVMX_ENABLE_DEBUG_PRINTS -static const char *modes[] = - { "UNKNOWN", "TX Halfplex", "Rx Halfplex", "Duplex" }; -#endif - -/* Default callbacks, can be overridden - * using cvmx_spi_get_callbacks/cvmx_spi_set_callbacks - */ -static cvmx_spi_callbacks_t cvmx_spi_callbacks = { - .reset_cb = cvmx_spi_reset_cb, - .calendar_setup_cb = cvmx_spi_calendar_setup_cb, - .clock_detect_cb = cvmx_spi_clock_detect_cb, - .training_cb = cvmx_spi_training_cb, - .calendar_sync_cb = cvmx_spi_calendar_sync_cb, - .interface_up_cb = cvmx_spi_interface_up_cb -}; - -/** - * Get current SPI4 initialization callbacks - * - * @callbacks: Pointer to the callbacks structure.to fill - * - * Returns Pointer to cvmx_spi_callbacks_t structure. - */ -void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t *callbacks) -{ - memcpy(callbacks, &cvmx_spi_callbacks, sizeof(cvmx_spi_callbacks)); -} - -/** - * Set new SPI4 initialization callbacks - * - * @new_callbacks: Pointer to an updated callbacks structure. - */ -void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t *new_callbacks) -{ - memcpy(&cvmx_spi_callbacks, new_callbacks, sizeof(cvmx_spi_callbacks)); -} - -/** - * Initialize and start the SPI interface. - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for clock synchronization in seconds - * @num_ports: Number of SPI ports to configure - * - * Returns Zero on success, negative of failure. - */ -int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout, - int num_ports) -{ - int res = -1; - - if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))) - return res; - - /* Callback to perform SPI4 reset */ - INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode); - - /* Callback to perform calendar setup */ - INVOKE_CB(cvmx_spi_callbacks.calendar_setup_cb, interface, mode, - num_ports); - - /* Callback to perform clock detection */ - INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout); - - /* Callback to perform SPI4 link training */ - INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout); - - /* Callback to perform calendar sync */ - INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, - timeout); - - /* Callback to handle interface coming up */ - INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode); - - return res; -} - -/** - * This routine restarts the SPI interface after it has lost synchronization - * with its correspondent system. - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for clock synchronization in seconds - * - * Returns Zero on success, negative of failure. - */ -int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout) -{ - int res = -1; - - if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))) - return res; - - cvmx_dprintf("SPI%d: Restart %s\n", interface, modes[mode]); - - /* Callback to perform SPI4 reset */ - INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode); - - /* NOTE: Calendar setup is not performed during restart */ - /* Refer to cvmx_spi_start_interface() for the full sequence */ - - /* Callback to perform clock detection */ - INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout); - - /* Callback to perform SPI4 link training */ - INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout); - - /* Callback to perform calendar sync */ - INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode, - timeout); - - /* Callback to handle interface coming up */ - INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode); - - return res; -} - -/** - * Callback to perform SPI4 reset - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode) -{ - union cvmx_spxx_dbg_deskew_ctl spxx_dbg_deskew_ctl; - union cvmx_spxx_clk_ctl spxx_clk_ctl; - union cvmx_spxx_bist_stat spxx_bist_stat; - union cvmx_spxx_int_msk spxx_int_msk; - union cvmx_stxx_int_msk stxx_int_msk; - union cvmx_spxx_trn4_ctl spxx_trn4_ctl; - int index; - uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; - - /* Disable SPI error events while we run BIST */ - spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface)); - cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0); - stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface)); - cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0); - - /* Run BIST in the SPI interface */ - cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0); - cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0); - spxx_clk_ctl.u64 = 0; - spxx_clk_ctl.s.runbist = 1; - cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); - cvmx_wait(10 * MS); - spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface)); - if (spxx_bist_stat.s.stat0) - cvmx_dprintf - ("ERROR SPI%d: BIST failed on receive datapath FIFO\n", - interface); - if (spxx_bist_stat.s.stat1) - cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n", - interface); - if (spxx_bist_stat.s.stat2) - cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n", - interface); - - /* Clear the calendar table after BIST to fix parity errors */ - for (index = 0; index < 32; index++) { - union cvmx_srxx_spi4_calx srxx_spi4_calx; - union cvmx_stxx_spi4_calx stxx_spi4_calx; - - srxx_spi4_calx.u64 = 0; - srxx_spi4_calx.s.oddpar = 1; - cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), - srxx_spi4_calx.u64); - - stxx_spi4_calx.u64 = 0; - stxx_spi4_calx.s.oddpar = 1; - cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), - stxx_spi4_calx.u64); - } - - /* Re enable reporting of error interrupts */ - cvmx_write_csr(CVMX_SPXX_INT_REG(interface), - cvmx_read_csr(CVMX_SPXX_INT_REG(interface))); - cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64); - cvmx_write_csr(CVMX_STXX_INT_REG(interface), - cvmx_read_csr(CVMX_STXX_INT_REG(interface))); - cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64); - - /* Setup the CLKDLY right in the middle */ - spxx_clk_ctl.u64 = 0; - spxx_clk_ctl.s.seetrn = 0; - spxx_clk_ctl.s.clkdly = 0x10; - spxx_clk_ctl.s.runbist = 0; - spxx_clk_ctl.s.statdrv = 0; - /* This should always be on the opposite edge as statdrv */ - spxx_clk_ctl.s.statrcv = 1; - spxx_clk_ctl.s.sndtrn = 0; - spxx_clk_ctl.s.drptrn = 0; - spxx_clk_ctl.s.rcvtrn = 0; - spxx_clk_ctl.s.srxdlck = 0; - cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); - cvmx_wait(100 * MS); - - /* Reset SRX0 DLL */ - spxx_clk_ctl.s.srxdlck = 1; - cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); - - /* Waiting for Inf0 Spi4 RX DLL to lock */ - cvmx_wait(100 * MS); - - /* Enable dynamic alignment */ - spxx_trn4_ctl.s.trntest = 0; - spxx_trn4_ctl.s.jitter = 1; - spxx_trn4_ctl.s.clr_boot = 1; - spxx_trn4_ctl.s.set_boot = 0; - if (OCTEON_IS_MODEL(OCTEON_CN58XX)) - spxx_trn4_ctl.s.maxdist = 3; - else - spxx_trn4_ctl.s.maxdist = 8; - spxx_trn4_ctl.s.macro_en = 1; - spxx_trn4_ctl.s.mux_en = 1; - cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64); - - spxx_dbg_deskew_ctl.u64 = 0; - cvmx_write_csr(CVMX_SPXX_DBG_DESKEW_CTL(interface), - spxx_dbg_deskew_ctl.u64); - - return 0; -} - -/** - * Callback to setup calendar and miscellaneous settings before clock detection - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @num_ports: Number of ports to configure on SPI - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, - int num_ports) -{ - int port; - int index; - if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { - union cvmx_srxx_com_ctl srxx_com_ctl; - union cvmx_srxx_spi4_stat srxx_spi4_stat; - - /* SRX0 number of Ports */ - srxx_com_ctl.u64 = 0; - srxx_com_ctl.s.prts = num_ports - 1; - srxx_com_ctl.s.st_en = 0; - srxx_com_ctl.s.inf_en = 0; - cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); - - /* SRX0 Calendar Table. This round robbins through all ports */ - port = 0; - index = 0; - while (port < num_ports) { - union cvmx_srxx_spi4_calx srxx_spi4_calx; - srxx_spi4_calx.u64 = 0; - srxx_spi4_calx.s.prt0 = port++; - srxx_spi4_calx.s.prt1 = port++; - srxx_spi4_calx.s.prt2 = port++; - srxx_spi4_calx.s.prt3 = port++; - srxx_spi4_calx.s.oddpar = - ~(cvmx_dpop(srxx_spi4_calx.u64) & 1); - cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface), - srxx_spi4_calx.u64); - index++; - } - srxx_spi4_stat.u64 = 0; - srxx_spi4_stat.s.len = num_ports; - srxx_spi4_stat.s.m = 1; - cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface), - srxx_spi4_stat.u64); - } - - if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { - union cvmx_stxx_arb_ctl stxx_arb_ctl; - union cvmx_gmxx_tx_spi_max gmxx_tx_spi_max; - union cvmx_gmxx_tx_spi_thresh gmxx_tx_spi_thresh; - union cvmx_gmxx_tx_spi_ctl gmxx_tx_spi_ctl; - union cvmx_stxx_spi4_stat stxx_spi4_stat; - union cvmx_stxx_spi4_dat stxx_spi4_dat; - - /* STX0 Config */ - stxx_arb_ctl.u64 = 0; - stxx_arb_ctl.s.igntpa = 0; - stxx_arb_ctl.s.mintrn = 0; - cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64); - - gmxx_tx_spi_max.u64 = 0; - gmxx_tx_spi_max.s.max1 = 8; - gmxx_tx_spi_max.s.max2 = 4; - gmxx_tx_spi_max.s.slice = 0; - cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface), - gmxx_tx_spi_max.u64); - - gmxx_tx_spi_thresh.u64 = 0; - gmxx_tx_spi_thresh.s.thresh = 4; - cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface), - gmxx_tx_spi_thresh.u64); - - gmxx_tx_spi_ctl.u64 = 0; - gmxx_tx_spi_ctl.s.tpa_clr = 0; - gmxx_tx_spi_ctl.s.cont_pkt = 0; - cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface), - gmxx_tx_spi_ctl.u64); - - /* STX0 Training Control */ - stxx_spi4_dat.u64 = 0; - /*Minimum needed by dynamic alignment */ - stxx_spi4_dat.s.alpha = 32; - stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20 */ - cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface), - stxx_spi4_dat.u64); - - /* STX0 Calendar Table. This round robbins through all ports */ - port = 0; - index = 0; - while (port < num_ports) { - union cvmx_stxx_spi4_calx stxx_spi4_calx; - stxx_spi4_calx.u64 = 0; - stxx_spi4_calx.s.prt0 = port++; - stxx_spi4_calx.s.prt1 = port++; - stxx_spi4_calx.s.prt2 = port++; - stxx_spi4_calx.s.prt3 = port++; - stxx_spi4_calx.s.oddpar = - ~(cvmx_dpop(stxx_spi4_calx.u64) & 1); - cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface), - stxx_spi4_calx.u64); - index++; - } - stxx_spi4_stat.u64 = 0; - stxx_spi4_stat.s.len = num_ports; - stxx_spi4_stat.s.m = 1; - cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface), - stxx_spi4_stat.u64); - } - - return 0; -} - -/** - * Callback to perform clock detection - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for clock synchronization in seconds - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout) -{ - int clock_transitions; - union cvmx_spxx_clk_stat stat; - uint64_t timeout_time; - uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; - - /* - * Regardless of operating mode, both Tx and Rx clocks must be - * present for the SPI interface to operate. - */ - cvmx_dprintf("SPI%d: Waiting to see TsClk...\n", interface); - timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; - /* - * Require 100 clock transitions in order to avoid any noise - * in the beginning. - */ - clock_transitions = 100; - do { - stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); - if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions) { - /* - * We've seen a clock transition, so decrement - * the number we still need. - */ - clock_transitions--; - cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64); - stat.s.s4clk0 = 0; - stat.s.s4clk1 = 0; - } - if (cvmx_get_cycle() > timeout_time) { - cvmx_dprintf("SPI%d: Timeout\n", interface); - return -1; - } - } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0); - - cvmx_dprintf("SPI%d: Waiting to see RsClk...\n", interface); - timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; - /* - * Require 100 clock transitions in order to avoid any noise in the - * beginning. - */ - clock_transitions = 100; - do { - stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); - if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions) { - /* - * We've seen a clock transition, so decrement - * the number we still need - */ - clock_transitions--; - cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64); - stat.s.d4clk0 = 0; - stat.s.d4clk1 = 0; - } - if (cvmx_get_cycle() > timeout_time) { - cvmx_dprintf("SPI%d: Timeout\n", interface); - return -1; - } - } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0); - - return 0; -} - -/** - * Callback to perform link training - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for link to be trained (in seconds) - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout) -{ - union cvmx_spxx_trn4_ctl spxx_trn4_ctl; - union cvmx_spxx_clk_stat stat; - uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; - uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; - int rx_training_needed; - - /* SRX0 & STX0 Inf0 Links are configured - begin training */ - union cvmx_spxx_clk_ctl spxx_clk_ctl; - spxx_clk_ctl.u64 = 0; - spxx_clk_ctl.s.seetrn = 0; - spxx_clk_ctl.s.clkdly = 0x10; - spxx_clk_ctl.s.runbist = 0; - spxx_clk_ctl.s.statdrv = 0; - /* This should always be on the opposite edge as statdrv */ - spxx_clk_ctl.s.statrcv = 1; - spxx_clk_ctl.s.sndtrn = 1; - spxx_clk_ctl.s.drptrn = 1; - spxx_clk_ctl.s.rcvtrn = 1; - spxx_clk_ctl.s.srxdlck = 1; - cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64); - cvmx_wait(1000 * MS); - - /* SRX0 clear the boot bit */ - spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface)); - spxx_trn4_ctl.s.clr_boot = 1; - cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64); - - /* Wait for the training sequence to complete */ - cvmx_dprintf("SPI%d: Waiting for training\n", interface); - cvmx_wait(1000 * MS); - /* Wait a really long time here */ - timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; - /* - * The HRM says we must wait for 34 + 16 * MAXDIST training sequences. - * We'll be pessimistic and wait for a lot more. - */ - rx_training_needed = 500; - do { - stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); - if (stat.s.srxtrn && rx_training_needed) { - rx_training_needed--; - cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64); - stat.s.srxtrn = 0; - } - if (cvmx_get_cycle() > timeout_time) { - cvmx_dprintf("SPI%d: Timeout\n", interface); - return -1; - } - } while (stat.s.srxtrn == 0); - - return 0; -} - -/** - * Callback to perform calendar data synchronization - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for calendar data in seconds - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout) -{ - uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000; - if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { - /* SRX0 interface should be good, send calendar data */ - union cvmx_srxx_com_ctl srxx_com_ctl; - cvmx_dprintf - ("SPI%d: Rx is synchronized, start sending calendar data\n", - interface); - srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface)); - srxx_com_ctl.s.inf_en = 1; - srxx_com_ctl.s.st_en = 1; - cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); - } - - if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { - /* STX0 has achieved sync */ - /* The corespondant board should be sending calendar data */ - /* Enable the STX0 STAT receiver. */ - union cvmx_spxx_clk_stat stat; - uint64_t timeout_time; - union cvmx_stxx_com_ctl stxx_com_ctl; - stxx_com_ctl.u64 = 0; - stxx_com_ctl.s.st_en = 1; - cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64); - - /* Waiting for calendar sync on STX0 STAT */ - cvmx_dprintf("SPI%d: Waiting to sync on STX[%d] STAT\n", - interface, interface); - timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout; - /* SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10) */ - do { - stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface)); - if (cvmx_get_cycle() > timeout_time) { - cvmx_dprintf("SPI%d: Timeout\n", interface); - return -1; - } - } while (stat.s.stxcal == 0); - } - - return 0; -} - -/** - * Callback to handle interface up - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode) -{ - union cvmx_gmxx_rxx_frm_min gmxx_rxx_frm_min; - union cvmx_gmxx_rxx_frm_max gmxx_rxx_frm_max; - union cvmx_gmxx_rxx_jabber gmxx_rxx_jabber; - - if (mode & CVMX_SPI_MODE_RX_HALFPLEX) { - union cvmx_srxx_com_ctl srxx_com_ctl; - srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface)); - srxx_com_ctl.s.inf_en = 1; - cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64); - cvmx_dprintf("SPI%d: Rx is now up\n", interface); - } - - if (mode & CVMX_SPI_MODE_TX_HALFPLEX) { - union cvmx_stxx_com_ctl stxx_com_ctl; - stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface)); - stxx_com_ctl.s.inf_en = 1; - cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64); - cvmx_dprintf("SPI%d: Tx is now up\n", interface); - } - - gmxx_rxx_frm_min.u64 = 0; - gmxx_rxx_frm_min.s.len = 64; - cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0, interface), - gmxx_rxx_frm_min.u64); - gmxx_rxx_frm_max.u64 = 0; - gmxx_rxx_frm_max.s.len = 64 * 1024 - 4; - cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0, interface), - gmxx_rxx_frm_max.u64); - gmxx_rxx_jabber.u64 = 0; - gmxx_rxx_jabber.s.cnt = 64 * 1024 - 4; - cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0, interface), gmxx_rxx_jabber.u64); - - return 0; -} diff --git a/drivers/staging/octeon/cvmx-spi.h b/drivers/staging/octeon/cvmx-spi.h deleted file mode 100644 index e814648953a5..000000000000 --- a/drivers/staging/octeon/cvmx-spi.h +++ /dev/null @@ -1,269 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/* - * - * This file contains defines for the SPI interface - */ -#ifndef __CVMX_SPI_H__ -#define __CVMX_SPI_H__ - -#include "cvmx-gmxx-defs.h" - -/* CSR typedefs have been moved to cvmx-csr-*.h */ - -typedef enum { - CVMX_SPI_MODE_UNKNOWN = 0, - CVMX_SPI_MODE_TX_HALFPLEX = 1, - CVMX_SPI_MODE_RX_HALFPLEX = 2, - CVMX_SPI_MODE_DUPLEX = 3 -} cvmx_spi_mode_t; - -/** Callbacks structure to customize SPI4 initialization sequence */ -typedef struct { - /** Called to reset SPI4 DLL */ - int (*reset_cb) (int interface, cvmx_spi_mode_t mode); - - /** Called to setup calendar */ - int (*calendar_setup_cb) (int interface, cvmx_spi_mode_t mode, - int num_ports); - - /** Called for Tx and Rx clock detection */ - int (*clock_detect_cb) (int interface, cvmx_spi_mode_t mode, - int timeout); - - /** Called to perform link training */ - int (*training_cb) (int interface, cvmx_spi_mode_t mode, int timeout); - - /** Called for calendar data synchronization */ - int (*calendar_sync_cb) (int interface, cvmx_spi_mode_t mode, - int timeout); - - /** Called when interface is up */ - int (*interface_up_cb) (int interface, cvmx_spi_mode_t mode); - -} cvmx_spi_callbacks_t; - -/** - * Return true if the supplied interface is configured for SPI - * - * @interface: Interface to check - * Returns True if interface is SPI - */ -static inline int cvmx_spi_is_spi_interface(int interface) -{ - uint64_t gmxState = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface)); - return (gmxState & 0x2) && (gmxState & 0x1); -} - -/** - * Initialize and start the SPI interface. - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for clock synchronization in seconds - * @num_ports: Number of SPI ports to configure - * - * Returns Zero on success, negative of failure. - */ -extern int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, - int timeout, int num_ports); - -/** - * This routine restarts the SPI interface after it has lost synchronization - * with its corespondant system. - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for clock synchronization in seconds - * Returns Zero on success, negative of failure. - */ -extern int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, - int timeout); - -/** - * Return non-zero if the SPI interface has a SPI4000 attached - * - * @interface: SPI interface the SPI4000 is connected to - * - * Returns - */ -static inline int cvmx_spi4000_is_present(int interface) -{ - return 0; -} - -/** - * Initialize the SPI4000 for use - * - * @interface: SPI interface the SPI4000 is connected to - */ -static inline int cvmx_spi4000_initialize(int interface) -{ - return 0; -} - -/** - * Poll all the SPI4000 port and check its speed - * - * @interface: Interface the SPI4000 is on - * @port: Port to poll (0-9) - * Returns Status of the port. 0=down. All other values the port is up. - */ -static inline union cvmx_gmxx_rxx_rx_inbnd cvmx_spi4000_check_speed( - int interface, - int port) -{ - union cvmx_gmxx_rxx_rx_inbnd r; - r.u64 = 0; - return r; -} - -/** - * Get current SPI4 initialization callbacks - * - * @callbacks: Pointer to the callbacks structure.to fill - * - * Returns Pointer to cvmx_spi_callbacks_t structure. - */ -extern void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t *callbacks); - -/** - * Set new SPI4 initialization callbacks - * - * @new_callbacks: Pointer to an updated callbacks structure. - */ -extern void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t *new_callbacks); - -/** - * Callback to perform SPI4 reset - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -extern int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode); - -/** - * Callback to setup calendar and miscellaneous settings before clock - * detection - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @num_ports: Number of ports to configure on SPI - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -extern int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode, - int num_ports); - -/** - * Callback to perform clock detection - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for clock synchronization in seconds - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -extern int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, - int timeout); - -/** - * Callback to perform link training - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for link to be trained (in seconds) - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -extern int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, - int timeout); - -/** - * Callback to perform calendar data synchronization - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * @timeout: Timeout to wait for calendar data in seconds - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -extern int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, - int timeout); - -/** - * Callback to handle interface up - * - * @interface: The identifier of the packet interface to configure and - * use as a SPI interface. - * @mode: The operating mode for the SPI interface. The interface - * can operate as a full duplex (both Tx and Rx data paths - * active) or as a halfplex (either the Tx data path is - * active or the Rx data path is active, but not both). - * - * Returns Zero on success, non-zero error code on failure (will cause - * SPI initialization to abort) - */ -extern int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode); - -#endif /* __CVMX_SPI_H__ */ diff --git a/drivers/staging/octeon/cvmx-spxx-defs.h b/drivers/staging/octeon/cvmx-spxx-defs.h deleted file mode 100644 index b16940e32c83..000000000000 --- a/drivers/staging/octeon/cvmx-spxx-defs.h +++ /dev/null @@ -1,347 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_SPXX_DEFS_H__ -#define __CVMX_SPXX_DEFS_H__ - -#define CVMX_SPXX_BCKPRS_CNT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000340ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_BIST_STAT(block_id) \ - CVMX_ADD_IO_SEG(0x00011800900007F8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_CLK_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000348ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_CLK_STAT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000350ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_DBG_DESKEW_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000368ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_DBG_DESKEW_STATE(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000370ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_DRV_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000358ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_ERR_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000320ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_INT_DAT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000318ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_INT_MSK(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000308ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_INT_REG(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000300ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_INT_SYNC(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000310ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_TPA_ACC(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000338ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_TPA_MAX(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000330ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_TPA_SEL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000328ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SPXX_TRN4_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000360ull + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_spxx_bckprs_cnt { - uint64_t u64; - struct cvmx_spxx_bckprs_cnt_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_spxx_bckprs_cnt_s cn38xx; - struct cvmx_spxx_bckprs_cnt_s cn38xxp2; - struct cvmx_spxx_bckprs_cnt_s cn58xx; - struct cvmx_spxx_bckprs_cnt_s cn58xxp1; -}; - -union cvmx_spxx_bist_stat { - uint64_t u64; - struct cvmx_spxx_bist_stat_s { - uint64_t reserved_3_63:61; - uint64_t stat2:1; - uint64_t stat1:1; - uint64_t stat0:1; - } s; - struct cvmx_spxx_bist_stat_s cn38xx; - struct cvmx_spxx_bist_stat_s cn38xxp2; - struct cvmx_spxx_bist_stat_s cn58xx; - struct cvmx_spxx_bist_stat_s cn58xxp1; -}; - -union cvmx_spxx_clk_ctl { - uint64_t u64; - struct cvmx_spxx_clk_ctl_s { - uint64_t reserved_17_63:47; - uint64_t seetrn:1; - uint64_t reserved_12_15:4; - uint64_t clkdly:5; - uint64_t runbist:1; - uint64_t statdrv:1; - uint64_t statrcv:1; - uint64_t sndtrn:1; - uint64_t drptrn:1; - uint64_t rcvtrn:1; - uint64_t srxdlck:1; - } s; - struct cvmx_spxx_clk_ctl_s cn38xx; - struct cvmx_spxx_clk_ctl_s cn38xxp2; - struct cvmx_spxx_clk_ctl_s cn58xx; - struct cvmx_spxx_clk_ctl_s cn58xxp1; -}; - -union cvmx_spxx_clk_stat { - uint64_t u64; - struct cvmx_spxx_clk_stat_s { - uint64_t reserved_11_63:53; - uint64_t stxcal:1; - uint64_t reserved_9_9:1; - uint64_t srxtrn:1; - uint64_t s4clk1:1; - uint64_t s4clk0:1; - uint64_t d4clk1:1; - uint64_t d4clk0:1; - uint64_t reserved_0_3:4; - } s; - struct cvmx_spxx_clk_stat_s cn38xx; - struct cvmx_spxx_clk_stat_s cn38xxp2; - struct cvmx_spxx_clk_stat_s cn58xx; - struct cvmx_spxx_clk_stat_s cn58xxp1; -}; - -union cvmx_spxx_dbg_deskew_ctl { - uint64_t u64; - struct cvmx_spxx_dbg_deskew_ctl_s { - uint64_t reserved_30_63:34; - uint64_t fallnop:1; - uint64_t fall8:1; - uint64_t reserved_26_27:2; - uint64_t sstep_go:1; - uint64_t sstep:1; - uint64_t reserved_22_23:2; - uint64_t clrdly:1; - uint64_t dec:1; - uint64_t inc:1; - uint64_t mux:1; - uint64_t offset:5; - uint64_t bitsel:5; - uint64_t offdly:6; - uint64_t dllfrc:1; - uint64_t dlldis:1; - } s; - struct cvmx_spxx_dbg_deskew_ctl_s cn38xx; - struct cvmx_spxx_dbg_deskew_ctl_s cn38xxp2; - struct cvmx_spxx_dbg_deskew_ctl_s cn58xx; - struct cvmx_spxx_dbg_deskew_ctl_s cn58xxp1; -}; - -union cvmx_spxx_dbg_deskew_state { - uint64_t u64; - struct cvmx_spxx_dbg_deskew_state_s { - uint64_t reserved_9_63:55; - uint64_t testres:1; - uint64_t unxterm:1; - uint64_t muxsel:2; - uint64_t offset:5; - } s; - struct cvmx_spxx_dbg_deskew_state_s cn38xx; - struct cvmx_spxx_dbg_deskew_state_s cn38xxp2; - struct cvmx_spxx_dbg_deskew_state_s cn58xx; - struct cvmx_spxx_dbg_deskew_state_s cn58xxp1; -}; - -union cvmx_spxx_drv_ctl { - uint64_t u64; - struct cvmx_spxx_drv_ctl_s { - uint64_t reserved_0_63:64; - } s; - struct cvmx_spxx_drv_ctl_cn38xx { - uint64_t reserved_16_63:48; - uint64_t stx4ncmp:4; - uint64_t stx4pcmp:4; - uint64_t srx4cmp:8; - } cn38xx; - struct cvmx_spxx_drv_ctl_cn38xx cn38xxp2; - struct cvmx_spxx_drv_ctl_cn58xx { - uint64_t reserved_24_63:40; - uint64_t stx4ncmp:4; - uint64_t stx4pcmp:4; - uint64_t reserved_10_15:6; - uint64_t srx4cmp:10; - } cn58xx; - struct cvmx_spxx_drv_ctl_cn58xx cn58xxp1; -}; - -union cvmx_spxx_err_ctl { - uint64_t u64; - struct cvmx_spxx_err_ctl_s { - uint64_t reserved_9_63:55; - uint64_t prtnxa:1; - uint64_t dipcls:1; - uint64_t dippay:1; - uint64_t reserved_4_5:2; - uint64_t errcnt:4; - } s; - struct cvmx_spxx_err_ctl_s cn38xx; - struct cvmx_spxx_err_ctl_s cn38xxp2; - struct cvmx_spxx_err_ctl_s cn58xx; - struct cvmx_spxx_err_ctl_s cn58xxp1; -}; - -union cvmx_spxx_int_dat { - uint64_t u64; - struct cvmx_spxx_int_dat_s { - uint64_t reserved_32_63:32; - uint64_t mul:1; - uint64_t reserved_14_30:17; - uint64_t calbnk:2; - uint64_t rsvop:4; - uint64_t prt:8; - } s; - struct cvmx_spxx_int_dat_s cn38xx; - struct cvmx_spxx_int_dat_s cn38xxp2; - struct cvmx_spxx_int_dat_s cn58xx; - struct cvmx_spxx_int_dat_s cn58xxp1; -}; - -union cvmx_spxx_int_msk { - uint64_t u64; - struct cvmx_spxx_int_msk_s { - uint64_t reserved_12_63:52; - uint64_t calerr:1; - uint64_t syncerr:1; - uint64_t diperr:1; - uint64_t tpaovr:1; - uint64_t rsverr:1; - uint64_t drwnng:1; - uint64_t clserr:1; - uint64_t spiovr:1; - uint64_t reserved_2_3:2; - uint64_t abnorm:1; - uint64_t prtnxa:1; - } s; - struct cvmx_spxx_int_msk_s cn38xx; - struct cvmx_spxx_int_msk_s cn38xxp2; - struct cvmx_spxx_int_msk_s cn58xx; - struct cvmx_spxx_int_msk_s cn58xxp1; -}; - -union cvmx_spxx_int_reg { - uint64_t u64; - struct cvmx_spxx_int_reg_s { - uint64_t reserved_32_63:32; - uint64_t spf:1; - uint64_t reserved_12_30:19; - uint64_t calerr:1; - uint64_t syncerr:1; - uint64_t diperr:1; - uint64_t tpaovr:1; - uint64_t rsverr:1; - uint64_t drwnng:1; - uint64_t clserr:1; - uint64_t spiovr:1; - uint64_t reserved_2_3:2; - uint64_t abnorm:1; - uint64_t prtnxa:1; - } s; - struct cvmx_spxx_int_reg_s cn38xx; - struct cvmx_spxx_int_reg_s cn38xxp2; - struct cvmx_spxx_int_reg_s cn58xx; - struct cvmx_spxx_int_reg_s cn58xxp1; -}; - -union cvmx_spxx_int_sync { - uint64_t u64; - struct cvmx_spxx_int_sync_s { - uint64_t reserved_12_63:52; - uint64_t calerr:1; - uint64_t syncerr:1; - uint64_t diperr:1; - uint64_t tpaovr:1; - uint64_t rsverr:1; - uint64_t drwnng:1; - uint64_t clserr:1; - uint64_t spiovr:1; - uint64_t reserved_2_3:2; - uint64_t abnorm:1; - uint64_t prtnxa:1; - } s; - struct cvmx_spxx_int_sync_s cn38xx; - struct cvmx_spxx_int_sync_s cn38xxp2; - struct cvmx_spxx_int_sync_s cn58xx; - struct cvmx_spxx_int_sync_s cn58xxp1; -}; - -union cvmx_spxx_tpa_acc { - uint64_t u64; - struct cvmx_spxx_tpa_acc_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_spxx_tpa_acc_s cn38xx; - struct cvmx_spxx_tpa_acc_s cn38xxp2; - struct cvmx_spxx_tpa_acc_s cn58xx; - struct cvmx_spxx_tpa_acc_s cn58xxp1; -}; - -union cvmx_spxx_tpa_max { - uint64_t u64; - struct cvmx_spxx_tpa_max_s { - uint64_t reserved_32_63:32; - uint64_t max:32; - } s; - struct cvmx_spxx_tpa_max_s cn38xx; - struct cvmx_spxx_tpa_max_s cn38xxp2; - struct cvmx_spxx_tpa_max_s cn58xx; - struct cvmx_spxx_tpa_max_s cn58xxp1; -}; - -union cvmx_spxx_tpa_sel { - uint64_t u64; - struct cvmx_spxx_tpa_sel_s { - uint64_t reserved_4_63:60; - uint64_t prtsel:4; - } s; - struct cvmx_spxx_tpa_sel_s cn38xx; - struct cvmx_spxx_tpa_sel_s cn38xxp2; - struct cvmx_spxx_tpa_sel_s cn58xx; - struct cvmx_spxx_tpa_sel_s cn58xxp1; -}; - -union cvmx_spxx_trn4_ctl { - uint64_t u64; - struct cvmx_spxx_trn4_ctl_s { - uint64_t reserved_13_63:51; - uint64_t trntest:1; - uint64_t jitter:3; - uint64_t clr_boot:1; - uint64_t set_boot:1; - uint64_t maxdist:5; - uint64_t macro_en:1; - uint64_t mux_en:1; - } s; - struct cvmx_spxx_trn4_ctl_s cn38xx; - struct cvmx_spxx_trn4_ctl_s cn38xxp2; - struct cvmx_spxx_trn4_ctl_s cn58xx; - struct cvmx_spxx_trn4_ctl_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-srxx-defs.h b/drivers/staging/octeon/cvmx-srxx-defs.h deleted file mode 100644 index d82b366c279f..000000000000 --- a/drivers/staging/octeon/cvmx-srxx-defs.h +++ /dev/null @@ -1,126 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_SRXX_DEFS_H__ -#define __CVMX_SRXX_DEFS_H__ - -#define CVMX_SRXX_COM_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000200ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SRXX_IGN_RX_FULL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000218ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SRXX_SPI4_CALX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000000ull + (((offset) & 31) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SRXX_SPI4_STAT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000208ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SRXX_SW_TICK_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000220ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_SRXX_SW_TICK_DAT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000228ull + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_srxx_com_ctl { - uint64_t u64; - struct cvmx_srxx_com_ctl_s { - uint64_t reserved_8_63:56; - uint64_t prts:4; - uint64_t st_en:1; - uint64_t reserved_1_2:2; - uint64_t inf_en:1; - } s; - struct cvmx_srxx_com_ctl_s cn38xx; - struct cvmx_srxx_com_ctl_s cn38xxp2; - struct cvmx_srxx_com_ctl_s cn58xx; - struct cvmx_srxx_com_ctl_s cn58xxp1; -}; - -union cvmx_srxx_ign_rx_full { - uint64_t u64; - struct cvmx_srxx_ign_rx_full_s { - uint64_t reserved_16_63:48; - uint64_t ignore:16; - } s; - struct cvmx_srxx_ign_rx_full_s cn38xx; - struct cvmx_srxx_ign_rx_full_s cn38xxp2; - struct cvmx_srxx_ign_rx_full_s cn58xx; - struct cvmx_srxx_ign_rx_full_s cn58xxp1; -}; - -union cvmx_srxx_spi4_calx { - uint64_t u64; - struct cvmx_srxx_spi4_calx_s { - uint64_t reserved_17_63:47; - uint64_t oddpar:1; - uint64_t prt3:4; - uint64_t prt2:4; - uint64_t prt1:4; - uint64_t prt0:4; - } s; - struct cvmx_srxx_spi4_calx_s cn38xx; - struct cvmx_srxx_spi4_calx_s cn38xxp2; - struct cvmx_srxx_spi4_calx_s cn58xx; - struct cvmx_srxx_spi4_calx_s cn58xxp1; -}; - -union cvmx_srxx_spi4_stat { - uint64_t u64; - struct cvmx_srxx_spi4_stat_s { - uint64_t reserved_16_63:48; - uint64_t m:8; - uint64_t reserved_7_7:1; - uint64_t len:7; - } s; - struct cvmx_srxx_spi4_stat_s cn38xx; - struct cvmx_srxx_spi4_stat_s cn38xxp2; - struct cvmx_srxx_spi4_stat_s cn58xx; - struct cvmx_srxx_spi4_stat_s cn58xxp1; -}; - -union cvmx_srxx_sw_tick_ctl { - uint64_t u64; - struct cvmx_srxx_sw_tick_ctl_s { - uint64_t reserved_14_63:50; - uint64_t eop:1; - uint64_t sop:1; - uint64_t mod:4; - uint64_t opc:4; - uint64_t adr:4; - } s; - struct cvmx_srxx_sw_tick_ctl_s cn38xx; - struct cvmx_srxx_sw_tick_ctl_s cn58xx; - struct cvmx_srxx_sw_tick_ctl_s cn58xxp1; -}; - -union cvmx_srxx_sw_tick_dat { - uint64_t u64; - struct cvmx_srxx_sw_tick_dat_s { - uint64_t dat:64; - } s; - struct cvmx_srxx_sw_tick_dat_s cn38xx; - struct cvmx_srxx_sw_tick_dat_s cn58xx; - struct cvmx_srxx_sw_tick_dat_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-stxx-defs.h b/drivers/staging/octeon/cvmx-stxx-defs.h deleted file mode 100644 index 4f209b62cae1..000000000000 --- a/drivers/staging/octeon/cvmx-stxx-defs.h +++ /dev/null @@ -1,292 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -#ifndef __CVMX_STXX_DEFS_H__ -#define __CVMX_STXX_DEFS_H__ - -#define CVMX_STXX_ARB_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000608ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_BCKPRS_CNT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000688ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_COM_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000600ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_DIP_CNT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000690ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_IGN_CAL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000610ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_INT_MSK(block_id) \ - CVMX_ADD_IO_SEG(0x00011800900006A0ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_INT_REG(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000698ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_INT_SYNC(block_id) \ - CVMX_ADD_IO_SEG(0x00011800900006A8ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_MIN_BST(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000618ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_SPI4_CALX(offset, block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000400ull + (((offset) & 31) * 8) + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_SPI4_DAT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000628ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_SPI4_STAT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000630ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_STAT_BYTES_HI(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000648ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_STAT_BYTES_LO(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000680ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_STAT_CTL(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000638ull + (((block_id) & 1) * 0x8000000ull)) -#define CVMX_STXX_STAT_PKT_XMT(block_id) \ - CVMX_ADD_IO_SEG(0x0001180090000640ull + (((block_id) & 1) * 0x8000000ull)) - -union cvmx_stxx_arb_ctl { - uint64_t u64; - struct cvmx_stxx_arb_ctl_s { - uint64_t reserved_6_63:58; - uint64_t mintrn:1; - uint64_t reserved_4_4:1; - uint64_t igntpa:1; - uint64_t reserved_0_2:3; - } s; - struct cvmx_stxx_arb_ctl_s cn38xx; - struct cvmx_stxx_arb_ctl_s cn38xxp2; - struct cvmx_stxx_arb_ctl_s cn58xx; - struct cvmx_stxx_arb_ctl_s cn58xxp1; -}; - -union cvmx_stxx_bckprs_cnt { - uint64_t u64; - struct cvmx_stxx_bckprs_cnt_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_stxx_bckprs_cnt_s cn38xx; - struct cvmx_stxx_bckprs_cnt_s cn38xxp2; - struct cvmx_stxx_bckprs_cnt_s cn58xx; - struct cvmx_stxx_bckprs_cnt_s cn58xxp1; -}; - -union cvmx_stxx_com_ctl { - uint64_t u64; - struct cvmx_stxx_com_ctl_s { - uint64_t reserved_4_63:60; - uint64_t st_en:1; - uint64_t reserved_1_2:2; - uint64_t inf_en:1; - } s; - struct cvmx_stxx_com_ctl_s cn38xx; - struct cvmx_stxx_com_ctl_s cn38xxp2; - struct cvmx_stxx_com_ctl_s cn58xx; - struct cvmx_stxx_com_ctl_s cn58xxp1; -}; - -union cvmx_stxx_dip_cnt { - uint64_t u64; - struct cvmx_stxx_dip_cnt_s { - uint64_t reserved_8_63:56; - uint64_t frmmax:4; - uint64_t dipmax:4; - } s; - struct cvmx_stxx_dip_cnt_s cn38xx; - struct cvmx_stxx_dip_cnt_s cn38xxp2; - struct cvmx_stxx_dip_cnt_s cn58xx; - struct cvmx_stxx_dip_cnt_s cn58xxp1; -}; - -union cvmx_stxx_ign_cal { - uint64_t u64; - struct cvmx_stxx_ign_cal_s { - uint64_t reserved_16_63:48; - uint64_t igntpa:16; - } s; - struct cvmx_stxx_ign_cal_s cn38xx; - struct cvmx_stxx_ign_cal_s cn38xxp2; - struct cvmx_stxx_ign_cal_s cn58xx; - struct cvmx_stxx_ign_cal_s cn58xxp1; -}; - -union cvmx_stxx_int_msk { - uint64_t u64; - struct cvmx_stxx_int_msk_s { - uint64_t reserved_8_63:56; - uint64_t frmerr:1; - uint64_t unxfrm:1; - uint64_t nosync:1; - uint64_t diperr:1; - uint64_t datovr:1; - uint64_t ovrbst:1; - uint64_t calpar1:1; - uint64_t calpar0:1; - } s; - struct cvmx_stxx_int_msk_s cn38xx; - struct cvmx_stxx_int_msk_s cn38xxp2; - struct cvmx_stxx_int_msk_s cn58xx; - struct cvmx_stxx_int_msk_s cn58xxp1; -}; - -union cvmx_stxx_int_reg { - uint64_t u64; - struct cvmx_stxx_int_reg_s { - uint64_t reserved_9_63:55; - uint64_t syncerr:1; - uint64_t frmerr:1; - uint64_t unxfrm:1; - uint64_t nosync:1; - uint64_t diperr:1; - uint64_t datovr:1; - uint64_t ovrbst:1; - uint64_t calpar1:1; - uint64_t calpar0:1; - } s; - struct cvmx_stxx_int_reg_s cn38xx; - struct cvmx_stxx_int_reg_s cn38xxp2; - struct cvmx_stxx_int_reg_s cn58xx; - struct cvmx_stxx_int_reg_s cn58xxp1; -}; - -union cvmx_stxx_int_sync { - uint64_t u64; - struct cvmx_stxx_int_sync_s { - uint64_t reserved_8_63:56; - uint64_t frmerr:1; - uint64_t unxfrm:1; - uint64_t nosync:1; - uint64_t diperr:1; - uint64_t datovr:1; - uint64_t ovrbst:1; - uint64_t calpar1:1; - uint64_t calpar0:1; - } s; - struct cvmx_stxx_int_sync_s cn38xx; - struct cvmx_stxx_int_sync_s cn38xxp2; - struct cvmx_stxx_int_sync_s cn58xx; - struct cvmx_stxx_int_sync_s cn58xxp1; -}; - -union cvmx_stxx_min_bst { - uint64_t u64; - struct cvmx_stxx_min_bst_s { - uint64_t reserved_9_63:55; - uint64_t minb:9; - } s; - struct cvmx_stxx_min_bst_s cn38xx; - struct cvmx_stxx_min_bst_s cn38xxp2; - struct cvmx_stxx_min_bst_s cn58xx; - struct cvmx_stxx_min_bst_s cn58xxp1; -}; - -union cvmx_stxx_spi4_calx { - uint64_t u64; - struct cvmx_stxx_spi4_calx_s { - uint64_t reserved_17_63:47; - uint64_t oddpar:1; - uint64_t prt3:4; - uint64_t prt2:4; - uint64_t prt1:4; - uint64_t prt0:4; - } s; - struct cvmx_stxx_spi4_calx_s cn38xx; - struct cvmx_stxx_spi4_calx_s cn38xxp2; - struct cvmx_stxx_spi4_calx_s cn58xx; - struct cvmx_stxx_spi4_calx_s cn58xxp1; -}; - -union cvmx_stxx_spi4_dat { - uint64_t u64; - struct cvmx_stxx_spi4_dat_s { - uint64_t reserved_32_63:32; - uint64_t alpha:16; - uint64_t max_t:16; - } s; - struct cvmx_stxx_spi4_dat_s cn38xx; - struct cvmx_stxx_spi4_dat_s cn38xxp2; - struct cvmx_stxx_spi4_dat_s cn58xx; - struct cvmx_stxx_spi4_dat_s cn58xxp1; -}; - -union cvmx_stxx_spi4_stat { - uint64_t u64; - struct cvmx_stxx_spi4_stat_s { - uint64_t reserved_16_63:48; - uint64_t m:8; - uint64_t reserved_7_7:1; - uint64_t len:7; - } s; - struct cvmx_stxx_spi4_stat_s cn38xx; - struct cvmx_stxx_spi4_stat_s cn38xxp2; - struct cvmx_stxx_spi4_stat_s cn58xx; - struct cvmx_stxx_spi4_stat_s cn58xxp1; -}; - -union cvmx_stxx_stat_bytes_hi { - uint64_t u64; - struct cvmx_stxx_stat_bytes_hi_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_stxx_stat_bytes_hi_s cn38xx; - struct cvmx_stxx_stat_bytes_hi_s cn38xxp2; - struct cvmx_stxx_stat_bytes_hi_s cn58xx; - struct cvmx_stxx_stat_bytes_hi_s cn58xxp1; -}; - -union cvmx_stxx_stat_bytes_lo { - uint64_t u64; - struct cvmx_stxx_stat_bytes_lo_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_stxx_stat_bytes_lo_s cn38xx; - struct cvmx_stxx_stat_bytes_lo_s cn38xxp2; - struct cvmx_stxx_stat_bytes_lo_s cn58xx; - struct cvmx_stxx_stat_bytes_lo_s cn58xxp1; -}; - -union cvmx_stxx_stat_ctl { - uint64_t u64; - struct cvmx_stxx_stat_ctl_s { - uint64_t reserved_5_63:59; - uint64_t clr:1; - uint64_t bckprs:4; - } s; - struct cvmx_stxx_stat_ctl_s cn38xx; - struct cvmx_stxx_stat_ctl_s cn38xxp2; - struct cvmx_stxx_stat_ctl_s cn58xx; - struct cvmx_stxx_stat_ctl_s cn58xxp1; -}; - -union cvmx_stxx_stat_pkt_xmt { - uint64_t u64; - struct cvmx_stxx_stat_pkt_xmt_s { - uint64_t reserved_32_63:32; - uint64_t cnt:32; - } s; - struct cvmx_stxx_stat_pkt_xmt_s cn38xx; - struct cvmx_stxx_stat_pkt_xmt_s cn38xxp2; - struct cvmx_stxx_stat_pkt_xmt_s cn58xx; - struct cvmx_stxx_stat_pkt_xmt_s cn58xxp1; -}; - -#endif diff --git a/drivers/staging/octeon/cvmx-wqe.h b/drivers/staging/octeon/cvmx-wqe.h deleted file mode 100644 index 653610953d28..000000000000 --- a/drivers/staging/octeon/cvmx-wqe.h +++ /dev/null @@ -1,397 +0,0 @@ -/***********************license start*************** - * Author: Cavium Networks - * - * Contact: support@caviumnetworks.com - * This file is part of the OCTEON SDK - * - * Copyright (c) 2003-2008 Cavium Networks - * - * This file 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 file is distributed in the hope that it will be useful, but - * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or - * NONINFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this file; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * or visit http://www.gnu.org/licenses/. - * - * This file may also be available under a different license from Cavium. - * Contact Cavium Networks for more information - ***********************license end**************************************/ - -/** - * - * This header file defines the work queue entry (wqe) data structure. - * Since this is a commonly used structure that depends on structures - * from several hardware blocks, those definitions have been placed - * in this file to create a single point of definition of the wqe - * format. - * Data structures are still named according to the block that they - * relate to. - * - */ - -#ifndef __CVMX_WQE_H__ -#define __CVMX_WQE_H__ - -#include "cvmx-packet.h" - - -#define OCT_TAG_TYPE_STRING(x) \ - (((x) == CVMX_POW_TAG_TYPE_ORDERED) ? "ORDERED" : \ - (((x) == CVMX_POW_TAG_TYPE_ATOMIC) ? "ATOMIC" : \ - (((x) == CVMX_POW_TAG_TYPE_NULL) ? "NULL" : \ - "NULL_NULL"))) - -/** - * HW decode / err_code in work queue entry - */ -typedef union { - uint64_t u64; - - /* Use this struct if the hardware determines that the packet is IP */ - struct { - /* HW sets this to the number of buffers used by this packet */ - uint64_t bufs:8; - /* HW sets to the number of L2 bytes prior to the IP */ - uint64_t ip_offset:8; - /* set to 1 if we found DSA/VLAN in the L2 */ - uint64_t vlan_valid:1; - /* Set to 1 if the DSA/VLAN tag is stacked */ - uint64_t vlan_stacked:1; - uint64_t unassigned:1; - /* HW sets to the DSA/VLAN CFI flag (valid when vlan_valid) */ - uint64_t vlan_cfi:1; - /* HW sets to the DSA/VLAN_ID field (valid when vlan_valid) */ - uint64_t vlan_id:12; - /* Ring Identifier (if PCIe). Requires PIP_GBL_CTL[RING_EN]=1 */ - uint64_t pr:4; - uint64_t unassigned2:8; - /* the packet needs to be decompressed */ - uint64_t dec_ipcomp:1; - /* the packet is either TCP or UDP */ - uint64_t tcp_or_udp:1; - /* the packet needs to be decrypted (ESP or AH) */ - uint64_t dec_ipsec:1; - /* the packet is IPv6 */ - uint64_t is_v6:1; - - /* - * (rcv_error, not_IP, IP_exc, is_frag, L4_error, - * software, etc.). - */ - - /* - * reserved for software use, hardware will clear on - * packet creation. - */ - uint64_t software:1; - /* exceptional conditions below */ - /* the receive interface hardware detected an L4 error - * (only applies if !is_frag) (only applies if - * !rcv_error && !not_IP && !IP_exc && !is_frag) - * failure indicated in err_code below, decode: - * - * - 1 = Malformed L4 - * - 2 = L4 Checksum Error: the L4 checksum value is - * - 3 = UDP Length Error: The UDP length field would - * make the UDP data longer than what remains in - * the IP packet (as defined by the IP header - * length field). - * - 4 = Bad L4 Port: either the source or destination - * TCP/UDP port is 0. - * - 8 = TCP FIN Only: the packet is TCP and only the - * FIN flag set. - * - 9 = TCP No Flags: the packet is TCP and no flags - * are set. - * - 10 = TCP FIN RST: the packet is TCP and both FIN - * and RST are set. - * - 11 = TCP SYN URG: the packet is TCP and both SYN - * and URG are set. - * - 12 = TCP SYN RST: the packet is TCP and both SYN - * and RST are set. - * - 13 = TCP SYN FIN: the packet is TCP and both SYN - * and FIN are set. - */ - uint64_t L4_error:1; - /* set if the packet is a fragment */ - uint64_t is_frag:1; - /* the receive interface hardware detected an IP error - * / exception (only applies if !rcv_error && !not_IP) - * failure indicated in err_code below, decode: - * - * - 1 = Not IP: the IP version field is neither 4 nor - * 6. - * - 2 = IPv4 Header Checksum Error: the IPv4 header - * has a checksum violation. - * - 3 = IP Malformed Header: the packet is not long - * enough to contain the IP header. - * - 4 = IP Malformed: the packet is not long enough - * to contain the bytes indicated by the IP - * header. Pad is allowed. - * - 5 = IP TTL Hop: the IPv4 TTL field or the IPv6 - * Hop Count field are zero. - * - 6 = IP Options - */ - uint64_t IP_exc:1; - /* - * Set if the hardware determined that the packet is a - * broadcast. - */ - uint64_t is_bcast:1; - /* - * St if the hardware determined that the packet is a - * multi-cast. - */ - uint64_t is_mcast:1; - /* - * Set if the packet may not be IP (must be zero in - * this case). - */ - uint64_t not_IP:1; - /* - * The receive interface hardware detected a receive - * error (must be zero in this case). - */ - uint64_t rcv_error:1; - /* lower err_code = first-level descriptor of the - * work */ - /* zero for packet submitted by hardware that isn't on - * the slow path */ - /* type is cvmx_pip_err_t */ - uint64_t err_code:8; - } s; - - /* use this to get at the 16 vlan bits */ - struct { - uint64_t unused1:16; - uint64_t vlan:16; - uint64_t unused2:32; - } svlan; - - /* - * use this struct if the hardware could not determine that - * the packet is ip. - */ - struct { - /* - * HW sets this to the number of buffers used by this - * packet. - */ - uint64_t bufs:8; - uint64_t unused:8; - /* set to 1 if we found DSA/VLAN in the L2 */ - uint64_t vlan_valid:1; - /* Set to 1 if the DSA/VLAN tag is stacked */ - uint64_t vlan_stacked:1; - uint64_t unassigned:1; - /* - * HW sets to the DSA/VLAN CFI flag (valid when - * vlan_valid) - */ - uint64_t vlan_cfi:1; - /* - * HW sets to the DSA/VLAN_ID field (valid when - * vlan_valid). - */ - uint64_t vlan_id:12; - /* - * Ring Identifier (if PCIe). Requires - * PIP_GBL_CTL[RING_EN]=1 - */ - uint64_t pr:4; - uint64_t unassigned2:12; - /* - * reserved for software use, hardware will clear on - * packet creation. - */ - uint64_t software:1; - uint64_t unassigned3:1; - /* - * set if the hardware determined that the packet is - * rarp. - */ - uint64_t is_rarp:1; - /* - * set if the hardware determined that the packet is - * arp - */ - uint64_t is_arp:1; - /* - * set if the hardware determined that the packet is a - * broadcast. - */ - uint64_t is_bcast:1; - /* - * set if the hardware determined that the packet is a - * multi-cast - */ - uint64_t is_mcast:1; - /* - * set if the packet may not be IP (must be one in - * this case) - */ - uint64_t not_IP:1; - /* The receive interface hardware detected a receive - * error. Failure indicated in err_code below, - * decode: - * - * - 1 = partial error: a packet was partially - * received, but internal buffering / bandwidth - * was not adequate to receive the entire - * packet. - * - 2 = jabber error: the RGMII packet was too large - * and is truncated. - * - 3 = overrun error: the RGMII packet is longer - * than allowed and had an FCS error. - * - 4 = oversize error: the RGMII packet is longer - * than allowed. - * - 5 = alignment error: the RGMII packet is not an - * integer number of bytes - * and had an FCS error (100M and 10M only). - * - 6 = fragment error: the RGMII packet is shorter - * than allowed and had an FCS error. - * - 7 = GMX FCS error: the RGMII packet had an FCS - * error. - * - 8 = undersize error: the RGMII packet is shorter - * than allowed. - * - 9 = extend error: the RGMII packet had an extend - * error. - * - 10 = length mismatch error: the RGMII packet had - * a length that did not match the length field - * in the L2 HDR. - * - 11 = RGMII RX error/SPI4 DIP4 Error: the RGMII - * packet had one or more data reception errors - * (RXERR) or the SPI4 packet had one or more - * DIP4 errors. - * - 12 = RGMII skip error/SPI4 Abort Error: the RGMII - * packet was not large enough to cover the - * skipped bytes or the SPI4 packet was - * terminated with an About EOPS. - * - 13 = RGMII nibble error/SPI4 Port NXA Error: the - * RGMII packet had a studder error (data not - * repeated - 10/100M only) or the SPI4 packet - * was sent to an NXA. - * - 16 = FCS error: a SPI4.2 packet had an FCS error. - * - 17 = Skip error: a packet was not large enough to - * cover the skipped bytes. - * - 18 = L2 header malformed: the packet is not long - * enough to contain the L2. - */ - - uint64_t rcv_error:1; - /* - * lower err_code = first-level descriptor of the - * work - */ - /* - * zero for packet submitted by hardware that isn't on - * the slow path - */ - /* type is cvmx_pip_err_t (union, so can't use directly */ - uint64_t err_code:8; - } snoip; - -} cvmx_pip_wqe_word2; - -/** - * Work queue entry format - * - * must be 8-byte aligned - */ -typedef struct { - - /***************************************************************** - * WORD 0 - * HW WRITE: the following 64 bits are filled by HW when a packet arrives - */ - - /** - * raw chksum result generated by the HW - */ - uint16_t hw_chksum; - /** - * Field unused by hardware - available for software - */ - uint8_t unused; - /** - * Next pointer used by hardware for list maintenance. - * May be written/read by HW before the work queue - * entry is scheduled to a PP - * (Only 36 bits used in Octeon 1) - */ - uint64_t next_ptr:40; - - /***************************************************************** - * WORD 1 - * HW WRITE: the following 64 bits are filled by HW when a packet arrives - */ - - /** - * HW sets to the total number of bytes in the packet - */ - uint64_t len:16; - /** - * HW sets this to input physical port - */ - uint64_t ipprt:6; - - /** - * HW sets this to what it thought the priority of the input packet was - */ - uint64_t qos:3; - - /** - * the group that the work queue entry will be scheduled to - */ - uint64_t grp:4; - /** - * the type of the tag (ORDERED, ATOMIC, NULL) - */ - uint64_t tag_type:3; - /** - * the synchronization/ordering tag - */ - uint64_t tag:32; - - /** - * WORD 2 HW WRITE: the following 64-bits are filled in by - * hardware when a packet arrives This indicates a variety of - * status and error conditions. - */ - cvmx_pip_wqe_word2 word2; - - /** - * Pointer to the first segment of the packet. - */ - union cvmx_buf_ptr packet_ptr; - - /** - * HW WRITE: octeon will fill in a programmable amount from the - * packet, up to (at most, but perhaps less) the amount - * needed to fill the work queue entry to 128 bytes - * - * If the packet is recognized to be IP, the hardware starts - * (except that the IPv4 header is padded for appropriate - * alignment) writing here where the IP header starts. If the - * packet is not recognized to be IP, the hardware starts - * writing the beginning of the packet here. - */ - uint8_t packet_data[96]; - - /** - * If desired, SW can make the work Q entry any length. For the - * purposes of discussion here, Assume 128B always, as this is all that - * the hardware deals with. - * - */ - -} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; - -#endif /* __CVMX_WQE_H__ */ diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h index 6a2cd50a17df..bdaec8d2ca0c 100644 --- a/drivers/staging/octeon/ethernet-defines.h +++ b/drivers/staging/octeon/ethernet-defines.h @@ -59,7 +59,7 @@ #ifndef __ETHERNET_DEFINES_H__ #define __ETHERNET_DEFINES_H__ -#include "cvmx-config.h" +#include <asm/octeon/cvmx-config.h> #define OCTEON_ETHERNET_VERSION "1.9" diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c index f18e3e140413..63800ba71d06 100644 --- a/drivers/staging/octeon/ethernet-mdio.c +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -38,9 +38,9 @@ #include "ethernet-mdio.h" #include "ethernet-util.h" -#include "cvmx-helper-board.h" +#include <asm/octeon/cvmx-helper-board.h> -#include "cvmx-smix-defs.h" +#include <asm/octeon/cvmx-smix-defs.h> static void cvm_oct_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c index 635bb86cdcff..78b6cb743769 100644 --- a/drivers/staging/octeon/ethernet-mem.c +++ b/drivers/staging/octeon/ethernet-mem.c @@ -32,7 +32,7 @@ #include "ethernet-defines.h" -#include "cvmx-fpa.h" +#include <asm/octeon/cvmx-fpa.h> /** * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c index c3d73f8431ae..d8f5f694ec35 100644 --- a/drivers/staging/octeon/ethernet-rgmii.c +++ b/drivers/staging/octeon/ethernet-rgmii.c @@ -37,11 +37,11 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> #include <asm/octeon/cvmx-ipd-defs.h> #include <asm/octeon/cvmx-npi-defs.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> DEFINE_SPINLOCK(global_register_lock); diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 8b307b428791..400df8cbee53 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -52,14 +52,14 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" -#include "cvmx-wqe.h" -#include "cvmx-fau.h" -#include "cvmx-pow.h" -#include "cvmx-pip.h" -#include "cvmx-scratch.h" - -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-wqe.h> +#include <asm/octeon/cvmx-fau.h> +#include <asm/octeon/cvmx-pow.h> +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-scratch.h> + +#include <asm/octeon/cvmx-gmxx-defs.h> struct cvm_napi_wrapper { struct napi_struct napi; diff --git a/drivers/staging/octeon/ethernet-rx.h b/drivers/staging/octeon/ethernet-rx.h index a0743b85d54e..9240c85ce241 100644 --- a/drivers/staging/octeon/ethernet-rx.h +++ b/drivers/staging/octeon/ethernet-rx.h @@ -24,7 +24,7 @@ * This file may also be available under a different license from Cavium. * Contact Cavium Networks for more information *********************************************************************/ -#include "cvmx-fau.h" +#include <asm/octeon/cvmx-fau.h> void cvm_oct_poll_controller(struct net_device *dev); void cvm_oct_rx_initialize(void); diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c index 5e148b512c97..d3e82430eba6 100644 --- a/drivers/staging/octeon/ethernet-sgmii.c +++ b/drivers/staging/octeon/ethernet-sgmii.c @@ -35,9 +35,9 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> int cvm_oct_sgmii_open(struct net_device *dev) { diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c index d0e2d514968a..af8d62818f13 100644 --- a/drivers/staging/octeon/ethernet-spi.c +++ b/drivers/staging/octeon/ethernet-spi.c @@ -35,11 +35,11 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-spi.h" +#include <asm/octeon/cvmx-spi.h> #include <asm/octeon/cvmx-npi-defs.h> -#include "cvmx-spxx-defs.h" -#include "cvmx-stxx-defs.h" +#include <asm/octeon/cvmx-spxx-defs.h> +#include <asm/octeon/cvmx-stxx-defs.h> static int number_spi_ports; static int need_retrain[2] = { 0, 0 }; diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 2542c3743904..56d74dc2fbd5 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -47,13 +47,13 @@ #include "ethernet-tx.h" #include "ethernet-util.h" -#include "cvmx-wqe.h" -#include "cvmx-fau.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-wqe.h> +#include <asm/octeon/cvmx-fau.h> +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> #define CVM_OCT_SKB_CB(skb) ((u64 *)((skb)->cb)) diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c index 861a4b3fe857..419f8c34ecdf 100644 --- a/drivers/staging/octeon/ethernet-xaui.c +++ b/drivers/staging/octeon/ethernet-xaui.c @@ -35,9 +35,9 @@ #include "octeon-ethernet.h" #include "ethernet-util.h" -#include "cvmx-helper.h" +#include <asm/octeon/cvmx-helper.h> -#include "cvmx-gmxx-defs.h" +#include <asm/octeon/cvmx-gmxx-defs.h> int cvm_oct_xaui_open(struct net_device *dev) { diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 076f86675ce6..9112cd882154 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -44,14 +44,14 @@ #include "ethernet-mdio.h" #include "ethernet-util.h" -#include "cvmx-pip.h" -#include "cvmx-pko.h" -#include "cvmx-fau.h" -#include "cvmx-ipd.h" -#include "cvmx-helper.h" - -#include "cvmx-gmxx-defs.h" -#include "cvmx-smix-defs.h" +#include <asm/octeon/cvmx-pip.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-fau.h> +#include <asm/octeon/cvmx-ipd.h> +#include <asm/octeon/cvmx-helper.h> + +#include <asm/octeon/cvmx-gmxx-defs.h> +#include <asm/octeon/cvmx-smix-defs.h> #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \ && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c index 02fafecd4773..897a3a99c794 100644 --- a/drivers/staging/quatech_usb2/quatech_usb2.c +++ b/drivers/staging/quatech_usb2/quatech_usb2.c @@ -16,7 +16,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; /* Version Information */ #define DRIVER_VERSION "v2.00" diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index c44e41af2880..1c5780f1571b 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -16,7 +16,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; /* Version Information */ #define DRIVER_VERSION "v2.14" diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h index 412b87947f66..e66579e6147a 100644 --- a/drivers/staging/speakup/speakup.h +++ b/drivers/staging/speakup/speakup.h @@ -116,7 +116,7 @@ extern int bleep_time, bell_pos; extern int spell_delay, key_echo; extern short punc_mask; extern short pitch_shift, synth_flags; -extern int quiet_boot; +extern bool quiet_boot; extern char *synth_name; extern struct bleep unprocessed_sound; diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index c241074a4b5e..2222d6919ef5 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -22,7 +22,7 @@ static struct spk_synth *synths[MAXSYNTHS]; struct spk_synth *synth; char pitch_buff[32] = ""; static int module_status; -int quiet_boot; +bool quiet_boot; struct speakup_info_t speakup_info = { .spinlock = __SPIN_LOCK_UNLOCKED(speakup_info.spinlock), diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 08a449b4abf9..f50582169b24 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -41,7 +41,7 @@ static void __exit tsi148_exit(void); /* Module parameter */ -static int err_chk; +static bool err_chk; static int geoid; static const char driver_name[] = "vme_tsi148"; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 6a1241c7f841..de88aa5566e5 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -118,7 +118,7 @@ static unsigned long board2; static unsigned long board3; static unsigned long board4; static unsigned long controller; -static int support_low_speed; +static bool support_low_speed; static unsigned long modem1; static unsigned long modem2; static unsigned long modem3; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index f32a2ea70100..aca2386c5ef1 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1605,4 +1605,27 @@ config SERIAL_XILINX_PS_UART_CONSOLE help Enable a Xilinx PS UART port to be the system console. +config SERIAL_AR933X + bool "AR933X serial port support" + depends on SOC_AR933X + select SERIAL_CORE + help + If you have an Atheros AR933X SOC based board and want to use the + built-in UART of the SoC, say Y to this option. + +config SERIAL_AR933X_CONSOLE + bool "Console on AR933X serial port" + depends on SERIAL_AR933X=y + select SERIAL_CORE_CONSOLE + help + Enable a built-in UART port of the AR933X to be the system console. + +config SERIAL_AR933X_NR_UARTS + int "Maximum number of AR933X serial ports" + depends on SERIAL_AR933X + default "2" + help + Set this to the number of serial ports you want the driver + to support. + endmenu diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 07e0494c6830..f5b01f2ce525 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -91,3 +91,4 @@ obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o +obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c new file mode 100644 index 000000000000..e4f60e2b87f3 --- /dev/null +++ b/drivers/tty/serial/ar933x_uart.c @@ -0,0 +1,688 @@ +/* + * Atheros AR933X SoC built-in UART driver + * + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * 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 <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> +#include <linux/serial.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include <asm/mach-ath79/ar933x_uart.h> +#include <asm/mach-ath79/ar933x_uart_platform.h> + +#define DRIVER_NAME "ar933x-uart" + +#define AR933X_DUMMY_STATUS_RD 0x01 + +static struct uart_driver ar933x_uart_driver; + +struct ar933x_uart_port { + struct uart_port port; + unsigned int ier; /* shadow Interrupt Enable Register */ +}; + +static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, + int offset) +{ + return readl(up->port.membase + offset); +} + +static inline void ar933x_uart_write(struct ar933x_uart_port *up, + int offset, unsigned int value) +{ + writel(value, up->port.membase + offset); +} + +static inline void ar933x_uart_rmw(struct ar933x_uart_port *up, + unsigned int offset, + unsigned int mask, + unsigned int val) +{ + unsigned int t; + + t = ar933x_uart_read(up, offset); + t &= ~mask; + t |= val; + ar933x_uart_write(up, offset, t); +} + +static inline void ar933x_uart_rmw_set(struct ar933x_uart_port *up, + unsigned int offset, + unsigned int val) +{ + ar933x_uart_rmw(up, offset, 0, val); +} + +static inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up, + unsigned int offset, + unsigned int val) +{ + ar933x_uart_rmw(up, offset, val, 0); +} + +static inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up) +{ + up->ier |= AR933X_UART_INT_TX_EMPTY; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) +{ + up->ier &= ~AR933X_UART_INT_TX_EMPTY; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) +{ + unsigned int rdata; + + rdata = ch & AR933X_UART_DATA_TX_RX_MASK; + rdata |= AR933X_UART_DATA_TX_CSR; + ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); +} + +static unsigned int ar933x_uart_tx_empty(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned long flags; + unsigned int rdata; + + spin_lock_irqsave(&up->port.lock, flags); + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + spin_unlock_irqrestore(&up->port.lock, flags); + + return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT; +} + +static unsigned int ar933x_uart_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR; +} + +static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void ar933x_uart_start_tx(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + ar933x_uart_start_tx_interrupt(up); +} + +static void ar933x_uart_stop_tx(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + ar933x_uart_stop_tx_interrupt(up); +} + +static void ar933x_uart_stop_rx(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + up->ier &= ~AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); +} + +static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + else + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void ar933x_uart_enable_ms(struct uart_port *port) +{ +} + +static void ar933x_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned int cs; + unsigned long flags; + unsigned int baud, scale; + + /* Only CS8 is supported */ + new->c_cflag &= ~CSIZE; + new->c_cflag |= CS8; + + /* Only one stop bit is supported */ + new->c_cflag &= ~CSTOPB; + + cs = 0; + if (new->c_cflag & PARENB) { + if (!(new->c_cflag & PARODD)) + cs |= AR933X_UART_CS_PARITY_EVEN; + else + cs |= AR933X_UART_CS_PARITY_ODD; + } else { + cs |= AR933X_UART_CS_PARITY_NONE; + } + + /* Mark/space parity is not supported */ + new->c_cflag &= ~CMSPAR; + + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + scale = (port->uartclk / (16 * baud)) - 1; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + + /* Update the per-port timeout. */ + uart_update_timeout(port, new->c_cflag, baud); + + up->port.ignore_status_mask = 0; + + /* ignore all characters if CREAD is not set */ + if ((new->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; + + ar933x_uart_write(up, AR933X_UART_CLOCK_REG, + scale << AR933X_UART_CLOCK_SCALE_S | 8192); + + /* setup configuration register */ + ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); + + /* enable host interrupt */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_HOST_INT_EN); + + spin_unlock_irqrestore(&up->port.lock, flags); + + if (tty_termios_baud_rate(new)) + tty_termios_encode_baud_rate(new, baud, baud); +} + +static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) +{ + struct tty_struct *tty; + int max_count = 256; + + tty = tty_port_tty_get(&up->port.state->port); + do { + unsigned int rdata; + unsigned char ch; + + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) + break; + + /* remove the character from the FIFO */ + ar933x_uart_write(up, AR933X_UART_DATA_REG, + AR933X_UART_DATA_RX_CSR); + + if (!tty) { + /* discard the data if no tty available */ + continue; + } + + up->port.icount.rx++; + ch = rdata & AR933X_UART_DATA_TX_RX_MASK; + + if (uart_handle_sysrq_char(&up->port, ch)) + continue; + + if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } while (max_count-- > 0); + + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } +} + +static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) +{ + struct circ_buf *xmit = &up->port.state->xmit; + int count; + + if (uart_tx_stopped(&up->port)) + return; + + count = up->port.fifosize; + do { + unsigned int rdata; + + rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) + break; + + if (up->port.x_char) { + ar933x_uart_putc(up, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + continue; + } + + if (uart_circ_empty(xmit)) + break; + + ar933x_uart_putc(up, xmit->buf[xmit->tail]); + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); + + if (!uart_circ_empty(xmit)) + ar933x_uart_start_tx_interrupt(up); +} + +static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) +{ + struct ar933x_uart_port *up = dev_id; + unsigned int status; + + status = ar933x_uart_read(up, AR933X_UART_CS_REG); + if ((status & AR933X_UART_CS_HOST_INT) == 0) + return IRQ_NONE; + + spin_lock(&up->port.lock); + + status = ar933x_uart_read(up, AR933X_UART_INT_REG); + status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + + if (status & AR933X_UART_INT_RX_VALID) { + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_RX_VALID); + ar933x_uart_rx_chars(up); + } + + if (status & AR933X_UART_INT_TX_EMPTY) { + ar933x_uart_write(up, AR933X_UART_INT_REG, + AR933X_UART_INT_TX_EMPTY); + ar933x_uart_stop_tx_interrupt(up); + ar933x_uart_tx_chars(up); + } + + spin_unlock(&up->port.lock); + + return IRQ_HANDLED; +} + +static int ar933x_uart_startup(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + unsigned long flags; + int ret; + + ret = request_irq(up->port.irq, ar933x_uart_interrupt, + up->port.irqflags, dev_name(up->port.dev), up); + if (ret) + return ret; + + spin_lock_irqsave(&up->port.lock, flags); + + /* Enable HOST interrupts */ + ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, + AR933X_UART_CS_HOST_INT_EN); + + /* Enable RX interrupts */ + up->ier = AR933X_UART_INT_RX_VALID; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + + spin_unlock_irqrestore(&up->port.lock, flags); + + return 0; +} + +static void ar933x_uart_shutdown(struct uart_port *port) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + /* Disable all interrupts */ + up->ier = 0; + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); + + /* Disable break condition */ + ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, + AR933X_UART_CS_TX_BREAK); + + free_irq(up->port.irq, up); +} + +static const char *ar933x_uart_type(struct uart_port *port) +{ + return (port->type == PORT_AR933X) ? "AR933X UART" : NULL; +} + +static void ar933x_uart_release_port(struct uart_port *port) +{ + /* Nothing to release ... */ +} + +static int ar933x_uart_request_port(struct uart_port *port) +{ + /* UARTs always present */ + return 0; +} + +static void ar933x_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_AR933X; +} + +static int ar933x_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (ser->type != PORT_UNKNOWN && + ser->type != PORT_AR933X) + return -EINVAL; + + if (ser->irq < 0 || ser->irq >= NR_IRQS) + return -EINVAL; + + if (ser->baud_base < 28800) + return -EINVAL; + + return 0; +} + +static struct uart_ops ar933x_uart_ops = { + .tx_empty = ar933x_uart_tx_empty, + .set_mctrl = ar933x_uart_set_mctrl, + .get_mctrl = ar933x_uart_get_mctrl, + .stop_tx = ar933x_uart_stop_tx, + .start_tx = ar933x_uart_start_tx, + .stop_rx = ar933x_uart_stop_rx, + .enable_ms = ar933x_uart_enable_ms, + .break_ctl = ar933x_uart_break_ctl, + .startup = ar933x_uart_startup, + .shutdown = ar933x_uart_shutdown, + .set_termios = ar933x_uart_set_termios, + .type = ar933x_uart_type, + .release_port = ar933x_uart_release_port, + .request_port = ar933x_uart_request_port, + .config_port = ar933x_uart_config_port, + .verify_port = ar933x_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_AR933X_CONSOLE + +static struct ar933x_uart_port * +ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; + +static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) +{ + unsigned int status; + unsigned int timeout = 60000; + + /* Wait up to 60ms for the character(s) to be sent. */ + do { + status = ar933x_uart_read(up, AR933X_UART_DATA_REG); + if (--timeout == 0) + break; + udelay(1); + } while ((status & AR933X_UART_DATA_TX_CSR) == 0); +} + +static void ar933x_uart_console_putchar(struct uart_port *port, int ch) +{ + struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; + + ar933x_uart_wait_xmitr(up); + ar933x_uart_putc(up, ch); +} + +static void ar933x_uart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct ar933x_uart_port *up = ar933x_console_ports[co->index]; + unsigned long flags; + unsigned int int_en; + int locked = 1; + + local_irq_save(flags); + + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + + /* + * First save the IER then disable the interrupts + */ + int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); + + uart_console_write(&up->port, s, count, ar933x_uart_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + ar933x_uart_wait_xmitr(up); + ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en); + + ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); + + if (locked) + spin_unlock(&up->port.lock); + + local_irq_restore(flags); +} + +static int ar933x_uart_console_setup(struct console *co, char *options) +{ + struct ar933x_uart_port *up; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= CONFIG_SERIAL_AR933X_NR_UARTS) + return -EINVAL; + + up = ar933x_console_ports[co->index]; + if (!up) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&up->port, co, baud, parity, bits, flow); +} + +static struct console ar933x_uart_console = { + .name = "ttyATH", + .write = ar933x_uart_console_write, + .device = uart_console_device, + .setup = ar933x_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &ar933x_uart_driver, +}; + +static void ar933x_uart_add_console_port(struct ar933x_uart_port *up) +{ + ar933x_console_ports[up->port.line] = up; +} + +#define AR933X_SERIAL_CONSOLE (&ar933x_uart_console) + +#else + +static inline void ar933x_uart_add_console_port(struct ar933x_uart_port *up) {} + +#define AR933X_SERIAL_CONSOLE NULL + +#endif /* CONFIG_SERIAL_AR933X_CONSOLE */ + +static struct uart_driver ar933x_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = "ttyATH", + .nr = CONFIG_SERIAL_AR933X_NR_UARTS, + .cons = AR933X_SERIAL_CONSOLE, +}; + +static int __devinit ar933x_uart_probe(struct platform_device *pdev) +{ + struct ar933x_uart_platform_data *pdata; + struct ar933x_uart_port *up; + struct uart_port *port; + struct resource *mem_res; + struct resource *irq_res; + int id; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -EINVAL; + + id = pdev->id; + if (id == -1) + id = 0; + + if (id > CONFIG_SERIAL_AR933X_NR_UARTS) + return -EINVAL; + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + dev_err(&pdev->dev, "no MEM resource\n"); + return -EINVAL; + } + + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq_res) { + dev_err(&pdev->dev, "no IRQ resource\n"); + return -EINVAL; + } + + up = kzalloc(sizeof(struct ar933x_uart_port), GFP_KERNEL); + if (!up) + return -ENOMEM; + + port = &up->port; + port->mapbase = mem_res->start; + + port->membase = ioremap(mem_res->start, AR933X_UART_REGS_SIZE); + if (!port->membase) { + ret = -ENOMEM; + goto err_free_up; + } + + port->line = id; + port->irq = irq_res->start; + port->dev = &pdev->dev; + port->type = PORT_AR933X; + port->iotype = UPIO_MEM32; + port->uartclk = pdata->uartclk; + + port->regshift = 2; + port->fifosize = AR933X_UART_FIFO_SIZE; + port->ops = &ar933x_uart_ops; + + ar933x_uart_add_console_port(up); + + ret = uart_add_one_port(&ar933x_uart_driver, &up->port); + if (ret) + goto err_unmap; + + platform_set_drvdata(pdev, up); + return 0; + +err_unmap: + iounmap(up->port.membase); +err_free_up: + kfree(up); + return ret; +} + +static int __devexit ar933x_uart_remove(struct platform_device *pdev) +{ + struct ar933x_uart_port *up; + + up = platform_get_drvdata(pdev); + platform_set_drvdata(pdev, NULL); + + if (up) { + uart_remove_one_port(&ar933x_uart_driver, &up->port); + iounmap(up->port.membase); + kfree(up); + } + + return 0; +} + +static struct platform_driver ar933x_uart_platform_driver = { + .probe = ar933x_uart_probe, + .remove = __devexit_p(ar933x_uart_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ar933x_uart_init(void) +{ + int ret; + + ar933x_uart_driver.nr = CONFIG_SERIAL_AR933X_NR_UARTS; + ret = uart_register_driver(&ar933x_uart_driver); + if (ret) + goto err_out; + + ret = platform_driver_register(&ar933x_uart_platform_driver); + if (ret) + goto err_unregister_uart_driver; + + return 0; + +err_unregister_uart_driver: + uart_unregister_driver(&ar933x_uart_driver); +err_out: + return ret; +} + +static void __exit ar933x_uart_exit(void) +{ + platform_driver_unregister(&ar933x_uart_platform_driver); + uart_unregister_driver(&ar933x_uart_driver); +} + +module_init(ar933x_uart_init); +module_exit(ar933x_uart_exit); + +MODULE_DESCRIPTION("Atheros AR933X UART driver"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index e67fb20490d2..ff8017f87914 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -850,7 +850,7 @@ static int mgsl_device_count; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load; +static bool break_on_load; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 0f6b796c95c5..a7efe538df00 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -456,7 +456,7 @@ static int synclinkmp_device_count = 0; * .text section address and breakpoint on module load. * This is useful for use with gdb and add-symbol-file command. */ -static int break_on_load = 0; +static bool break_on_load = 0; /* * Driver major number, defaults to zero to get auto diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index b42092e1f164..98dd9e49b684 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -73,9 +73,9 @@ static const char speedtch_driver_name[] = "speedtch"; #define DEFAULT_SW_BUFFERING 0 static unsigned int altsetting = 0; /* zero means: use the default */ -static int dl_512_first = DEFAULT_DL_512_FIRST; -static int enable_isoc = DEFAULT_ENABLE_ISOC; -static int sw_buffering = DEFAULT_SW_BUFFERING; +static bool dl_512_first = DEFAULT_DL_512_FIRST; +static bool enable_isoc = DEFAULT_ENABLE_ISOC; +static bool sw_buffering = DEFAULT_SW_BUFFERING; #define DEFAULT_B_MAX_DSL 8128 #define DEFAULT_MODEM_MODE 11 diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 00f171a7a8a0..01ea5d7421d4 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -542,7 +542,7 @@ static int modem_index; static unsigned int debug; static unsigned int altsetting[NB_MODEM] = { [0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; -static int sync_wait[NB_MODEM]; +static bool sync_wait[NB_MODEM]; static char *cmv_file[NB_MODEM]; static int annex[NB_MODEM]; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3af5e2dd1d82..8df4b76465ac 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -93,7 +93,7 @@ struct async { u8 bulk_status; }; -static int usbfs_snoop; +static bool usbfs_snoop; module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 79d339e2e700..a0613d8f9be7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -102,7 +102,7 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; /* cycle leds on hubs that aren't blinking for attention */ -static int blinkenlights = 0; +static bool blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); @@ -131,12 +131,12 @@ MODULE_PARM_DESC(initial_descriptor_timeout, * otherwise the new scheme is used. If that fails and "use_both_schemes" * is set, then the driver will make another attempt, using the other scheme. */ -static int old_scheme_first = 0; +static bool old_scheme_first = 0; module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(old_scheme_first, "start with the old device initialization scheme"); -static int use_both_schemes = 1; +static bool use_both_schemes = 1; module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(use_both_schemes, "try the other device initialization scheme if the " @@ -2026,7 +2026,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_ADDRESS_TRIES 2 #define GET_DESCRIPTOR_TRIES 2 #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) -#define USE_NEW_SCHEME(i) ((i) / 2 == old_scheme_first) +#define USE_NEW_SCHEME(i) ((i) / 2 == (int)old_scheme_first) #define HUB_ROOT_RESET_TIME 50 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 1382c90d0834..8ca9f994a280 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -47,7 +47,7 @@ const char *usbcore_name = "usbcore"; -static int nousb; /* Disable USB when built into kernel image */ +static bool nousb; /* Disable USB when built into kernel image */ #ifdef CONFIG_USB_SUSPEND static int usb_autosuspend_delay = 2; /* Default delay value, diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index e9a2c5c44454..c16ff55a74e8 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -152,15 +152,15 @@ static const char *ep_string[] = { }; /* DMA usage flag */ -static int use_dma = 1; +static bool use_dma = 1; /* packet per buffer dma */ -static int use_dma_ppb = 1; +static bool use_dma_ppb = 1; /* with per descr. update */ -static int use_dma_ppb_du; +static bool use_dma_ppb_du; /* buffer fill mode */ static int use_dma_bufferfill_mode; /* full speed only mode */ -static int use_fullspeed; +static bool use_fullspeed; /* tx buffer size for high speed */ static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE; diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 0cd764d59351..a28f6ffcd0f3 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -250,9 +250,9 @@ static struct usb_configuration rndis_config_driver = { /*-------------------------------------------------------------------------*/ #ifdef CONFIG_USB_ETH_EEM -static int use_eem = 1; +static bool use_eem = 1; #else -static int use_eem; +static bool use_eem; #endif module_param(use_eem, bool, 0); MODULE_PARM_DESC(use_eem, "use CDC EEM mode"); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index e0f30fc70e45..47766f0e7caa 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -303,16 +303,16 @@ MODULE_LICENSE("Dual BSD/GPL"); static struct { char *file[FSG_MAX_LUNS]; char *serial; - int ro[FSG_MAX_LUNS]; - int nofua[FSG_MAX_LUNS]; + bool ro[FSG_MAX_LUNS]; + bool nofua[FSG_MAX_LUNS]; unsigned int num_filenames; unsigned int num_ros; unsigned int num_nofuas; unsigned int nluns; - int removable; - int can_stall; - int cdrom; + bool removable; + bool can_stall; + bool cdrom; char *transport_parm; char *protocol_parm; diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 4c81d540bc26..7322d293213e 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -69,7 +69,7 @@ static const char * const ep_name[] = { * * If use_dma is disabled, pio will be used instead. */ -static int use_dma = 0; +static bool use_dma = 0; module_param(use_dma, bool, 0644); /* diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index cf1f36454d08..cdedd1336745 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -90,8 +90,8 @@ static const char *const ep_name [] = { * Some gadget drivers work better with the dma support here than others. * These two parameters let you use PIO or more aggressive DMA. */ -static int use_dma = 1; -static int use_dma_chaining = 0; +static bool use_dma = 1; +static bool use_dma_chaining = 0; /* "modprobe net2280 use_dma=n" etc */ module_param (use_dma, bool, S_IRUGO); @@ -112,7 +112,7 @@ module_param (fifo_mode, ushort, 0644); * USB suspend requests will be ignored. This is acceptable for * self-powered devices */ -static int enable_suspend = 0; +static bool enable_suspend = 0; /* "modprobe net2280 enable_suspend=1" etc */ module_param (enable_suspend, bool, S_IRUGO); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 7db5bbe6251b..576cd8578b45 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -98,7 +98,7 @@ module_param (fifo_mode, uint, 0); MODULE_PARM_DESC (fifo_mode, "endpoint configuration"); #ifdef USE_DMA -static unsigned use_dma = 1; +static bool use_dma = 1; /* "modprobe omap_udc use_dma=y", or else as a kernel * boot parameter "omap_udc:use_dma=y" diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index dd2313cce1d3..a3fcaae4bc2a 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -359,7 +359,7 @@ struct pch_udc_dev { static const char ep0_string[] = "ep0in"; static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ struct pch_udc_dev *pch_udc; /* pointer to device object */ -static int speed_fs; +static bool speed_fs; module_param_named(speed_fs, speed_fs, bool, S_IRUGO); MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index ed1b816e58d8..ad9e5b2df642 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -123,11 +123,11 @@ MODULE_AUTHOR("Al Borchers"); MODULE_AUTHOR("David Brownell"); MODULE_LICENSE("GPL"); -static int use_acm = true; +static bool use_acm = true; module_param(use_acm, bool, 0); MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes"); -static int use_obex = false; +static bool use_obex = false; module_param(use_obex, bool, 0); MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no"); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 20697cc132d1..31d34832907e 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -81,7 +81,7 @@ module_param(buflen, uint, 0); * work better with hosts where config changes are problematic or * controllers (like original superh) that only support one config. */ -static int loopdefault = 0; +static bool loopdefault = 0; module_param(loopdefault, bool, S_IRUGO|S_IWUSR); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4c0c9734251d..91413cac97be 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -219,7 +219,7 @@ config USB_CNS3XXX_EHCI config USB_EHCI_ATH79 bool "EHCI support for AR7XXX/AR9XXX SoCs" - depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X) + depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) select USB_EHCI_ROOT_HUB_TT default y ---help--- diff --git a/drivers/usb/host/alchemy-common.c b/drivers/usb/host/alchemy-common.c index b4192c964d0d..936af8359fb2 100644 --- a/drivers/usb/host/alchemy-common.c +++ b/drivers/usb/host/alchemy-common.c @@ -52,9 +52,263 @@ USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ USBCFG_OME) +/* Au1300 USB config registers */ +#define USB_DWC_CTRL1 0x00 +#define USB_DWC_CTRL2 0x04 +#define USB_VBUS_TIMER 0x10 +#define USB_SBUS_CTRL 0x14 +#define USB_MSR_ERR 0x18 +#define USB_DWC_CTRL3 0x1C +#define USB_DWC_CTRL4 0x20 +#define USB_OTG_STATUS 0x28 +#define USB_DWC_CTRL5 0x2C +#define USB_DWC_CTRL6 0x30 +#define USB_DWC_CTRL7 0x34 +#define USB_PHY_STATUS 0xC0 +#define USB_INT_STATUS 0xC4 +#define USB_INT_ENABLE 0xC8 + +#define USB_DWC_CTRL1_OTGD 0x04 /* set to DISable OTG */ +#define USB_DWC_CTRL1_HSTRS 0x02 /* set to ENable EHCI */ +#define USB_DWC_CTRL1_DCRS 0x01 /* set to ENable UDC */ + +#define USB_DWC_CTRL2_PHY1RS 0x04 /* set to enable PHY1 */ +#define USB_DWC_CTRL2_PHY0RS 0x02 /* set to enable PHY0 */ +#define USB_DWC_CTRL2_PHYRS 0x01 /* set to enable PHY */ + +#define USB_DWC_CTRL3_OHCI1_CKEN (1 << 19) +#define USB_DWC_CTRL3_OHCI0_CKEN (1 << 18) +#define USB_DWC_CTRL3_EHCI0_CKEN (1 << 17) +#define USB_DWC_CTRL3_OTG0_CKEN (1 << 16) + +#define USB_SBUS_CTRL_SBCA 0x04 /* coherent access */ + +#define USB_INTEN_FORCE 0x20 +#define USB_INTEN_PHY 0x10 +#define USB_INTEN_UDC 0x08 +#define USB_INTEN_EHCI 0x04 +#define USB_INTEN_OHCI1 0x02 +#define USB_INTEN_OHCI0 0x01 static DEFINE_SPINLOCK(alchemy_usb_lock); +static inline void __au1300_usb_phyctl(void __iomem *base, int enable) +{ + unsigned long r, s; + + r = __raw_readl(base + USB_DWC_CTRL2); + s = __raw_readl(base + USB_DWC_CTRL3); + + s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | + USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; + + if (enable) { + /* simply enable all PHYs */ + r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | + USB_DWC_CTRL2_PHYRS; + __raw_writel(r, base + USB_DWC_CTRL2); + wmb(); + } else if (!s) { + /* no USB block active, do disable all PHYs */ + r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | + USB_DWC_CTRL2_PHYRS); + __raw_writel(r, base + USB_DWC_CTRL2); + wmb(); + } +} + +static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) +{ + unsigned long r; + + if (enable) { + __raw_writel(1, base + USB_DWC_CTRL7); /* start OHCI clock */ + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); /* enable OHCI block */ + r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN + : USB_DWC_CTRL3_OHCI1_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); /* power up the PHYs */ + + r = __raw_readl(base + USB_INT_ENABLE); + r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + /* reset the OHCI start clock bit */ + __raw_writel(0, base + USB_DWC_CTRL7); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN + : USB_DWC_CTRL3_OHCI1_CKEN); + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_ehci_control(void __iomem *base, int enable) +{ + unsigned long r; + + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL3); + r |= USB_DWC_CTRL3_EHCI0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_HSTRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + + r = __raw_readl(base + USB_INT_ENABLE); + r |= USB_INTEN_EHCI; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~USB_INTEN_EHCI; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_HSTRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~USB_DWC_CTRL3_EHCI0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_udc_control(void __iomem *base, int enable) +{ + unsigned long r; + + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_DCRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + + r = __raw_readl(base + USB_INT_ENABLE); + r |= USB_INTEN_UDC; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + } else { + r = __raw_readl(base + USB_INT_ENABLE); + r &= ~USB_INTEN_UDC; + __raw_writel(r, base + USB_INT_ENABLE); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_DCRS; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline void __au1300_otg_control(void __iomem *base, int enable) +{ + unsigned long r; + if (enable) { + r = __raw_readl(base + USB_DWC_CTRL3); + r |= USB_DWC_CTRL3_OTG0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL1); + r &= ~USB_DWC_CTRL1_OTGD; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + __au1300_usb_phyctl(base, enable); + } else { + r = __raw_readl(base + USB_DWC_CTRL1); + r |= USB_DWC_CTRL1_OTGD; + __raw_writel(r, base + USB_DWC_CTRL1); + wmb(); + + r = __raw_readl(base + USB_DWC_CTRL3); + r &= ~USB_DWC_CTRL3_OTG0_CKEN; + __raw_writel(r, base + USB_DWC_CTRL3); + wmb(); + + __au1300_usb_phyctl(base, enable); + } +} + +static inline int au1300_usb_control(int block, int enable) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + int ret = 0; + + switch (block) { + case ALCHEMY_USB_OHCI0: + __au1300_ohci_control(base, enable, 0); + break; + case ALCHEMY_USB_OHCI1: + __au1300_ohci_control(base, enable, 1); + break; + case ALCHEMY_USB_EHCI0: + __au1300_ehci_control(base, enable); + break; + case ALCHEMY_USB_UDC0: + __au1300_udc_control(base, enable); + break; + case ALCHEMY_USB_OTG0: + __au1300_otg_control(base, enable); + break; + default: + ret = -ENODEV; + } + return ret; +} + +static inline void au1300_usb_init(void) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + + /* set some sane defaults. Note: we don't fiddle with DWC_CTRL4 + * here at all: Port 2 routing (EHCI or UDC) must be set either + * by boot firmware or platform init code; I can't autodetect + * a sane setting. + */ + __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ + wmb(); + __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ + wmb(); + __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ + wmb(); + __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ + wmb(); + /* set coherent access bit */ + __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); + wmb(); +} static inline void __au1200_ohci_control(void __iomem *base, int enable) { @@ -233,6 +487,9 @@ int alchemy_usb_control(int block, int enable) case ALCHEMY_CPU_AU1200: ret = au1200_usb_control(block, enable); break; + case ALCHEMY_CPU_AU1300: + ret = au1300_usb_control(block, enable); + break; default: ret = -ENODEV; } @@ -281,6 +538,20 @@ static void au1200_usb_pm(int susp) } } +static void au1300_usb_pm(int susp) +{ + void __iomem *base = + (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + /* remember Port2 routing */ + if (susp) { + alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); + } else { + au1300_usb_init(); + __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); + wmb(); + } +} + static void alchemy_usb_pm(int susp) { switch (alchemy_get_cputype()) { @@ -295,6 +566,9 @@ static void alchemy_usb_pm(int susp) case ALCHEMY_CPU_AU1200: au1200_usb_pm(susp); break; + case ALCHEMY_CPU_AU1300: + au1300_usb_pm(susp); + break; } } @@ -328,6 +602,9 @@ static int __init alchemy_usb_init(void) case ALCHEMY_CPU_AU1200: au1200_usb_init(); break; + case ALCHEMY_CPU_AU1300: + au1300_usb_init(); + break; } register_syscore_ops(&alchemy_usb_pm_ops); diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c index afb6743cf094..f1424f9bc363 100644 --- a/drivers/usb/host/ehci-ath79.c +++ b/drivers/usb/host/ehci-ath79.c @@ -33,6 +33,10 @@ static const struct platform_device_id ehci_ath79_id_table[] = { .driver_data = EHCI_ATH79_IP_V2, }, { + .name = "ar933x-ehci", + .driver_data = EHCI_ATH79_IP_V2, + }, + { /* terminating entry */ }, }; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e311a511529b..a007a9fe0f87 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -112,7 +112,7 @@ module_param (park, uint, S_IRUGO); MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets"); /* for flakey hardware, ignore overcurrent indicators */ -static int ignore_oc = 0; +static bool ignore_oc = 0; module_param (ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 40d886adff53..4ea63b2cac42 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -89,7 +89,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) { - int ret; + int ret, unit; struct usb_hcd *hcd; if (usb_disabled()) @@ -120,7 +120,9 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) goto err2; } - if (alchemy_usb_control(ALCHEMY_USB_OHCI0, 1)) { + unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; + if (alchemy_usb_control(unit, 1)) { printk(KERN_INFO "%s: controller init failed!\n", pdev->name); ret = -ENODEV; goto err3; @@ -135,7 +137,7 @@ static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) return ret; } - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); + alchemy_usb_control(unit, 0); err3: iounmap(hcd->regs); err2: @@ -148,9 +150,12 @@ err1: static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + int unit; + unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? + ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; usb_remove_hcd(hcd); - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); + alchemy_usb_control(unit, 0); iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 5f5a63241436..34b9edd86651 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -115,13 +115,13 @@ static inline void sb800_prefetch(struct ohci_hcd *ohci, int on) /* Some boards misreport power switching/overcurrent */ -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param (distrust_firmware, bool, 0); MODULE_PARM_DESC (distrust_firmware, "true to distrust firmware power/overcurrent setup"); /* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */ -static int no_handshake = 0; +static bool no_handshake = 0; module_param (no_handshake, bool, 0); MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 6f62de5c6e35..015c7c62ed49 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -233,7 +233,7 @@ module_param(park, uint, S_IRUGO); MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); /* For flakey hardware, ignore overcurrent indicators */ -static int ignore_oc; +static bool ignore_oc; module_param(ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC(ignore_oc, "ignore bogus hardware overcurrent indications"); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 533d12cca371..16dd6a6abf00 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -74,7 +74,7 @@ MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) INT_MODULE_PARM(testing, 0); /* Some boards misreport power switching/overcurrent*/ -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" "t setup"); diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index c8ae199cfbb8..6b5eb1017e2c 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -59,7 +59,7 @@ #define DRIVER_DESC "USB Universal Host Controller Interface driver" /* for flakey hardware, ignore overcurrent indicators */ -static int ignore_oc; +static bool ignore_oc; module_param(ignore_oc, bool, S_IRUGO); MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 2dbe600fbc11..a4a3c7cd4a11 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -53,7 +53,7 @@ MODULE_AUTHOR("Tony Olech"); MODULE_DESCRIPTION("FTDI ELAN driver"); MODULE_LICENSE("GPL"); #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static int distrust_firmware = 1; +static bool distrust_firmware = 1; module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" "t setup"); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 2453a39b4794..4fd0dc835ae5 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); /* Module parameters */ static DEFINE_MUTEX(iowarrior_mutex); -static int debug = 0; +static bool debug = 0; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "debug=1 enables debugging messages"); diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 53be7aef6308..66bc376005d2 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -750,7 +750,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) * So this module parameter lets the heuristic be disabled. When using * gadgetfs, the heuristic will probably need to be disabled. */ -static int cppi_rx_rndis = 1; +static bool cppi_rx_rndis = 1; module_param(cppi_rx_rndis, bool, 0); MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f6ff7923048b..56cf0243979e 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1586,7 +1586,7 @@ irqreturn_t musb_interrupt(struct musb *musb) EXPORT_SYMBOL_GPL(musb_interrupt); #ifndef CONFIG_MUSB_PIO_ONLY -static int __initdata use_dma = 1; +static bool __initdata use_dma = 1; /* "modprobe ... use_dma=0" etc */ module_param(use_dma, bool, 0); diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index 07ccea9ada40..74fe6e62e0f7 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -30,7 +30,7 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mfd/abx500.h> -#include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500/ab8500.h> #define AB8500_MAIN_WD_CTRL_REG 0x01 #define AB8500_USB_LINE_STAT_REG 0x80 diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index b43d07df4c44..123bf9155339 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -52,7 +52,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* Vendor and Product ID */ #define AIRCABLE_VID 0x16CA diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 18e875b92e00..69328dcfd91a 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -37,7 +37,7 @@ #include <linux/mutex.h> #include <linux/spinlock.h> -static int debug; +static bool debug; /* * Version information */ diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index f9f29b289f2f..29ffeb6279c7 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -37,7 +37,7 @@ #include <linux/usb/serial.h> #include "belkin_sa.h" -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 0e77511060c0..5e53cc59e652 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -70,7 +70,7 @@ #define CH341_NBREAK_BITS_REG2 0x40 -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x4348, 0x5523) }, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index adfe660ed008..fba1147ed916 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -49,7 +49,7 @@ static void cp210x_break_ctl(struct tty_struct *, int); static int cp210x_startup(struct usb_serial *); static void cp210x_dtr_rts(struct usb_serial_port *p, int on); -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 98bf83349838..6bc3802a581a 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -43,7 +43,7 @@ #define CYBERJACK_LOCAL_BUF_SIZE 32 -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 07680d6b792b..3bdeafa29c24 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -46,10 +46,10 @@ #include "cypress_m8.h" -static int debug; -static int stats; +static bool debug; +static bool stats; static int interval; -static int unstable_bauds; +static bool unstable_bauds; /* * Version Information diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 6d26a77d0f2a..b23bebd721a1 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -251,7 +251,7 @@ static int digi_read_oob_callback(struct urb *urb); /* Statics */ -static int debug; +static bool debug; static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 504b5585ea45..aced6817bf95 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -28,7 +28,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c290df97108e..01b6404df395 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -55,7 +55,7 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB FTDI Serial Converters Driver" -static int debug; +static bool debug; static __u16 vendor = FTDI_VID; static __u16 product; diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index e21ce9ddfc63..5d4b099dcf8b 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -16,7 +16,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1404, 0xcddc) }, diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index bf12565f8e87..21343378c322 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -42,7 +42,7 @@ static int initial_mode = 1; /* debug flag */ -static int debug; +static bool debug; #define GARMIN_VENDOR_ID 0x091E diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index abd2ee2b2f99..0497575e4799 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -191,7 +191,7 @@ static const struct divisor_table_entry divisor_table[] = { }; /* local variables */ -static int debug; +static bool debug; static atomic_t CmdUrbs; /* Number of outstanding Command Write Urbs */ diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index e44d375edaad..65bf06aa591a 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -210,10 +210,10 @@ static unsigned char OperationalMajorVersion; static unsigned char OperationalMinorVersion; static unsigned short OperationalBuildNumber; -static int debug; +static bool debug; static int closing_wait = EDGE_CLOSING_WAIT; -static int ignore_cpu_rev; +static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 36f5cbe90485..06053a920dd8 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -34,7 +34,7 @@ #define DRIVER_DESC "USB PocketPC PDA driver" static __u16 product, vendor; -static int debug; +static bool debug; static int connect_retries = KP_RETRIES; static int initial_wait; diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 5170799d6e94..6f9356f3f99e 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -147,7 +147,7 @@ static struct usb_driver usb_ipw_driver = { .no_dynamic_id = 1, }; -static int debug; +static bool debug; static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) { diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 0c537da0d3cd..84a396e83671 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -45,7 +45,7 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Johan Hovold <jhovold@gmail.com>" #define DRIVER_DESC "USB IR Dongle driver" -static int debug; +static bool debug; /* if overridden by the user, then use their value for the size of the read and * write urbs */ diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 64d0ffd4440b..3077a4436976 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -34,9 +34,9 @@ #ifdef CONFIG_USB_SERIAL_DEBUG -static int debug = 1; +static bool debug = 1; #else -static int debug; +static bool debug; #endif /* @@ -65,7 +65,7 @@ static int clockmode = 1; static int cdmode = 1; static int iuu_cardin; static int iuu_cardout; -static int xmas; +static bool xmas; static int vcc_default = 5; static void read_rxcmd_callback(struct urb *urb); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index bc8dc203e818..4cc36c761801 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -45,7 +45,7 @@ #include <linux/usb/serial.h> #include "keyspan.h" -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index a40615674a68..7c62a7048302 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -31,7 +31,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* make a simple define to handle if we are compiling keyspan_pda or xircom support */ #if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 19373cb7c5bf..fc064e1442ca 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -49,7 +49,7 @@ #include <linux/usb/serial.h> #include "kl5kusb105.h" -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a975bb80303f..27fa9c8a77b0 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -45,7 +45,7 @@ #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" -static int debug; +static bool debug; /* * Function prototypes diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 19d112f51b97..4554ee49e635 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -71,7 +71,7 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; }; -static int debug; +static bool debug; static struct usb_serial_driver moschip7720_2port_driver; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 55cfd6265b98..03b5e249e95e 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -263,7 +263,7 @@ struct moschip_port { }; -static int debug; +static bool debug; /* * mos7840_set_reg_sync diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 1f00f243c26c..b28f1db0195f 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -21,7 +21,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 45a8c55881d3..8b8d58a2ac12 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -23,7 +23,7 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -static int debug; +static bool debug; /* * Version Information diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 691f57a9d712..262ded9e076b 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -32,7 +32,7 @@ * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ #define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x065a, 0x0009) }, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c96b6b6509fb..420d9857394a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1234,7 +1234,7 @@ static struct usb_serial_driver option_1port_device = { #endif }; -static int debug; +static bool debug; /* per port private data */ diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 2161d1c3c089..e287fd32682c 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -74,7 +74,7 @@ static struct usb_driver oti6858_driver = { .no_dynamic_id = 1, }; -static int debug; +static bool debug; /* requests */ #define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 329295615d06..3d8cda57ce7a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -36,7 +36,7 @@ */ #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" -static int debug; +static bool debug; #define PL2303_CLOSING_WAIT (30*HZ) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index aa9367f5b421..1d5deee3be52 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -22,7 +22,7 @@ #define DRIVER_AUTHOR "Qualcomm Inc" #define DRIVER_DESC "Qualcomm USB Serial driver" -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index a36e2313eed0..d074b3740dcb 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -81,9 +81,9 @@ #define CONFIG_USB_SERIAL_SAFE_PADDED 0 #endif -static int debug; -static int safe = 1; -static int padded = CONFIG_USB_SERIAL_SAFE_PADDED; +static bool debug; +static bool safe = 1; +static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED; #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold <jhovold@gmail.com>" diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index f2485429172f..fdae0a4407cb 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -46,8 +46,8 @@ allocations > PAGE_SIZE and the number of packets in a page is an integer 512 is the largest possible packet on EHCI */ -static int debug; -static int nmea; +static bool debug; +static bool nmea; /* Used in interface blacklisting */ struct sierra_iface_info { diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 180ea6c7911c..d7f5eee18f00 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -33,7 +33,7 @@ #define DRIVER_VERSION "v0.10" #define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" -static int debug; +static bool debug; #define SPCP8x5_007_VID 0x04FC #define SPCP8x5_007_PID 0x0201 diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 87362e48796e..7697858d8858 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -46,7 +46,7 @@ #define FULLPWRBIT 0x00000080 #define NEXT_BOARD_POWER_BIT 0x00000004 -static int debug; +static bool debug; /* Version Information */ #define DRIVER_VERSION "v0.1" diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index c70cc012d03f..50651cf4fc61 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -20,7 +20,7 @@ #include <linux/usb/serial.h> #include <linux/uaccess.h> -static int debug; +static bool debug; static const struct usb_device_id id_table[] = { { USB_DEVICE(0x05e0, 0x0600) }, diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 4af21f46096e..8468eb769a29 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -150,7 +150,7 @@ static int ti_download_firmware(struct ti_device *tdev); /* Data */ /* module parameters */ -static int debug; +static bool debug; static int closing_wait = TI_DEFAULT_CLOSING_WAIT; static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; static unsigned int vendor_3410_count; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index ce6c1a65a544..611b206591cb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -61,7 +61,7 @@ static struct usb_driver usb_serial_driver = { drivers depend on it. */ -static int debug; +static bool debug; /* initially all NULL */ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; static DEFINE_MUTEX(table_lock); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index d555ca9567b8..c88657dd31c8 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -37,7 +37,7 @@ #include <linux/serial.h> #include "usb-wwan.h" -static int debug; +static bool debug; void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 1c11959a7d58..210e4b10dc11 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -52,7 +52,7 @@ static int palm_os_4_probe(struct usb_serial *serial, const struct usb_device_id *id); /* Parameters that may be passed into the module. */ -static int debug; +static bool debug; static __u16 vendor; static __u16 product; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 11af903cb09f..7e0acf5c8e38 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -36,7 +36,7 @@ #include <linux/ihex.h> #include "whiteheat.h" /* WhiteHEAT specific commands */ -static int debug; +static bool debug; #ifndef CMSPAR #define CMSPAR 0 diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d83e967e4e15..6ca0c407c144 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1763,16 +1763,16 @@ config FB_AU1100 au1100fb:panel=<name>. config FB_AU1200 - bool "Au1200 LCD Driver" + bool "Au1200/Au1300 LCD Driver" depends on (FB = y) && MIPS_ALCHEMY select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT select FB_SYS_FOPS help - This is the framebuffer driver for the AMD Au1200 SOC. It can drive - various panels and CRTs by passing in kernel cmd line option - au1200fb:panel=<name>. + This is the framebuffer driver for the Au1200/Au1300 SOCs. + It can drive various panels and CRTs by passing in kernel cmd line + option au1200fb:panel=<name>. config FB_VT8500 bool "VT8500 LCD Driver" @@ -2413,7 +2413,6 @@ source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" source "drivers/video/backlight/Kconfig" -source "drivers/video/display/Kconfig" if VT source "drivers/video/console/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9b9d8fff7732..142606814d98 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -13,7 +13,7 @@ fb-objs := $(fb-y) obj-$(CONFIG_VT) += console/ obj-$(CONFIG_LOGO) += logo/ -obj-y += backlight/ display/ +obj-y += backlight/ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 5ea6596dd824..f23cae094f1b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -152,10 +152,10 @@ - hsstrt: Start of horizontal synchronization pulse - hsstop: End of horizontal synchronization pulse - - htotal: Last value on the line (i.e. line length = htotal+1) + - htotal: Last value on the line (i.e. line length = htotal + 1) - vsstrt: Start of vertical synchronization pulse - vsstop: End of vertical synchronization pulse - - vtotal: Last line value (i.e. number of lines = vtotal+1) + - vtotal: Last line value (i.e. number of lines = vtotal + 1) - hcenter: Start of vertical retrace for interlace You can specify the blanking timings independently. Currently I just set @@ -184,7 +184,7 @@ clock): - diwstrt_h: Horizontal start of the visible window - - diwstop_h: Horizontal stop+1(*) of the visible window + - diwstop_h: Horizontal stop + 1(*) of the visible window - diwstrt_v: Vertical start of the visible window - diwstop_v: Vertical stop of the visible window - ddfstrt: Horizontal start of display DMA @@ -193,7 +193,7 @@ Sprite positioning: - - sprstrt_h: Horizontal start-4 of sprite + - sprstrt_h: Horizontal start - 4 of sprite - sprstrt_v: Vertical start of sprite (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. @@ -212,21 +212,21 @@ display parameters. Here's what I found out: - ddfstrt and ddfstop are best aligned to 64 pixels. - - the chipset needs 64+4 horizontal pixels after the DMA start before the - first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to - display the first pixel on the line too. Increase diwstrt_h for virtual - screen panning. + - the chipset needs 64 + 4 horizontal pixels after the DMA start before + the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want + to display the first pixel on the line too. Increase diwstrt_h for + virtual screen panning. - the display DMA always fetches 64 pixels at a time (fmode = 3). - - ddfstop is ddfstrt+#pixels-64. - - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1 - more than htotal. + - ddfstop is ddfstrt+#pixels - 64. + - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can + be 1 more than htotal. - hscroll simply adds a delay to the display output. Smooth horizontal - panning needs an extra 64 pixels on the left to prefetch the pixels that - `fall off' on the left. + panning needs an extra 64 pixels on the left to prefetch the pixels that + `fall off' on the left. - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane - DMA, so it's best to make the DMA start as late as possible. + DMA, so it's best to make the DMA start as late as possible. - you really don't want to make ddfstrt < 128, since this will steal DMA - cycles from the other DMA channels (audio, floppy and Chip RAM refresh). + cycles from the other DMA channels (audio, floppy and Chip RAM refresh). - I make diwstop_h and diwstop_v as large as possible. General dependencies @@ -234,8 +234,8 @@ - all values are SHRES pixel (35ns) - table 1:fetchstart table 2:prefetch table 3:fetchsize - ------------------ ---------------- ----------------- + table 1:fetchstart table 2:prefetch table 3:fetchsize + ------------------ ---------------- ----------------- Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES -------------#------+-----+------#------+-----+------#------+-----+------ Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 @@ -245,21 +245,21 @@ - chipset needs 4 pixels before the first pixel is output - ddfstrt must be aligned to fetchstart (table 1) - chipset needs also prefetch (table 2) to get first pixel data, so - ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch + ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch - for horizontal panning decrease diwstrt_h - the length of a fetchline must be aligned to fetchsize (table 3) - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit - moved to optimize use of dma (useful for OCS/ECS overscan displays) - - ddfstop is ddfstrt+ddfsize-fetchsize + moved to optimize use of dma (useful for OCS/ECS overscan displays) + - ddfstop is ddfstrt + ddfsize - fetchsize - If C= didn't change anything for AGA, then at following positions the - dma bus is already used: - ddfstrt < 48 -> memory refresh - < 96 -> disk dma - < 160 -> audio dma - < 192 -> sprite 0 dma - < 416 -> sprite dma (32 per sprite) + dma bus is already used: + ddfstrt < 48 -> memory refresh + < 96 -> disk dma + < 160 -> audio dma + < 192 -> sprite 0 dma + < 416 -> sprite dma (32 per sprite) - in accordance with the hardware reference manual a hardware stop is at - 192, but AGA (ECS?) can go below this. + 192, but AGA (ECS?) can go below this. DMA priorities -------------- @@ -269,7 +269,7 @@ the hardware cursor: - if you want to start display DMA too early, you lose the ability to - do smooth horizontal panning (xpanstep 1 -> 64). + do smooth horizontal panning (xpanstep 1 -> 64). - if you want to go even further, you lose the hardware cursor too. IMHO a hardware cursor is more important for X than horizontal scrolling, @@ -286,8 +286,8 @@ Standard VGA timings -------------------- - xres yres left right upper lower hsync vsync - ---- ---- ---- ----- ----- ----- ----- ----- + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- 80x25 720 400 27 45 35 12 108 2 80x30 720 480 27 45 30 9 108 2 @@ -297,8 +297,8 @@ As a comparison, graphics/monitor.h suggests the following: - xres yres left right upper lower hsync vsync - ---- ---- ---- ----- ----- ----- ----- ----- + xres yres left right upper lower hsync vsync + ---- ---- ---- ----- ----- ----- ----- ----- VGA 640 480 52 112 24 19 112 - 2 + VGA70 640 400 52 112 27 21 112 - 2 - @@ -309,10 +309,10 @@ VSYNC HSYNC Vertical size Vertical total ----- ----- ------------- -------------- - + + Reserved Reserved - + - 400 414 - - + 350 362 - - - 480 496 + + + Reserved Reserved + + - 400 414 + - + 350 362 + - - 480 496 Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 @@ -326,33 +326,34 @@ ----------- - a scanline is 64 µs long, of which 52.48 µs are visible. This is about - 736 visible 70 ns pixels per line. + 736 visible 70 ns pixels per line. - we have 625 scanlines, of which 575 are visible (interlaced); after - rounding this becomes 576. + rounding this becomes 576. RETMA -> NTSC ------------- - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about - 736 visible 70 ns pixels per line. + 736 visible 70 ns pixels per line. - we have 525 scanlines, of which 485 are visible (interlaced); after - rounding this becomes 484. + rounding this becomes 484. Thus if you want a PAL compatible display, you have to do the following: - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast - timings are to be used. - - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an - interlaced, 312 for a non-interlaced and 156 for a doublescanned - display. - - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES, - 908 for a HIRES and 454 for a LORES display. + timings are to be used. + - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an + interlaced, 312 for a non-interlaced and 156 for a doublescanned + display. + - make sure left_margin + xres + right_margin + hsync_len = 1816 for a + SHRES, 908 for a HIRES and 454 for a LORES display. - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), - left_margin+2*hsync_len must be greater or equal. + left_margin + 2 * hsync_len must be greater or equal. - the upper visible part begins at 48 (interlaced; non-interlaced:24, - doublescanned:12), upper_margin+2*vsync_len must be greater or equal. + doublescanned:12), upper_margin + 2 * vsync_len must be greater or + equal. - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync - of 4 scanlines + of 4 scanlines The settings for a NTSC compatible display are straightforward. @@ -361,7 +362,7 @@ anything about horizontal/vertical synchronization nor refresh rates. - -- Geert -- + -- Geert -- *******************************************************************************/ @@ -540,45 +541,45 @@ static u_short maxfmode, chipset; * Various macros */ -#define up2(v) (((v)+1) & -2) +#define up2(v) (((v) + 1) & -2) #define down2(v) ((v) & -2) #define div2(v) ((v)>>1) #define mod2(v) ((v) & 1) -#define up4(v) (((v)+3) & -4) +#define up4(v) (((v) + 3) & -4) #define down4(v) ((v) & -4) -#define mul4(v) ((v)<<2) +#define mul4(v) ((v) << 2) #define div4(v) ((v)>>2) #define mod4(v) ((v) & 3) -#define up8(v) (((v)+7) & -8) +#define up8(v) (((v) + 7) & -8) #define down8(v) ((v) & -8) #define div8(v) ((v)>>3) #define mod8(v) ((v) & 7) -#define up16(v) (((v)+15) & -16) +#define up16(v) (((v) + 15) & -16) #define down16(v) ((v) & -16) #define div16(v) ((v)>>4) #define mod16(v) ((v) & 15) -#define up32(v) (((v)+31) & -32) +#define up32(v) (((v) + 31) & -32) #define down32(v) ((v) & -32) #define div32(v) ((v)>>5) #define mod32(v) ((v) & 31) -#define up64(v) (((v)+63) & -64) +#define up64(v) (((v) + 63) & -64) #define down64(v) ((v) & -64) #define div64(v) ((v)>>6) #define mod64(v) ((v) & 63) -#define upx(x,v) (((v)+(x)-1) & -(x)) -#define downx(x,v) ((v) & -(x)) -#define modx(x,v) ((v) & ((x)-1)) +#define upx(x, v) (((v) + (x) - 1) & -(x)) +#define downx(x, v) ((v) & -(x)) +#define modx(x, v) ((v) & ((x) - 1)) /* if x1 is not a constant, this macro won't make real sense :-) */ #ifdef __mc68000__ #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ - "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;}) + "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) #else /* We know a bit about the numbers, so we can do it this way */ #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ @@ -607,7 +608,7 @@ static u_short maxfmode, chipset; #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ -#define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ +#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ #define DUMMYSPRITEMEMSIZE (8) static u_long spritememory; @@ -634,9 +635,9 @@ static u_long min_fstrt = 192; * Copper Instructions */ -#define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val)) -#define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val)) -#define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe) +#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) +#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) +#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) #define CEND (0xfffffffe) @@ -709,7 +710,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite; * Current Video Mode */ -static struct amifb_par { +struct amifb_par { /* General Values */ @@ -772,15 +773,6 @@ static struct amifb_par { /* Additional AGA Hardware Registers */ u_short fmode; /* vmode */ -} currentpar; - - -static struct fb_info fb_info = { - .fix = { - .id = "Amiga ", - .visual = FB_VISUAL_PSEUDOCOLOR, - .accel = FB_ACCEL_AMIGABLITT - } }; @@ -820,116 +812,123 @@ static u_short is_lace = 0; /* Screen is laced */ static struct fb_videomode ami_modedb[] __initdata = { - /* - * AmigaOS Video Modes - * - * If you change these, make sure to update DEFMODE_* as well! - */ - - { - /* 640x200, 15 kHz, 60 Hz (NTSC) */ - "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, - FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ - "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, - FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x256, 15 kHz, 50 Hz (PAL) */ - "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, - FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ - "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, - FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x480, 29 kHz, 57 Hz */ - "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x960, 29 kHz, 57 Hz interlaced */ - "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x200, 15 kHz, 72 Hz */ - "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 15 kHz, 72 Hz interlaced */ - "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 29 kHz, 68 Hz */ - "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x800, 29 kHz, 68 Hz interlaced */ - "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 800x300, 23 kHz, 70 Hz */ - "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 800x600, 23 kHz, 70 Hz interlaced */ - "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x200, 27 kHz, 57 Hz doublescan */ - "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, - 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP - }, { - /* 640x400, 27 kHz, 57 Hz */ - "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x800, 27 kHz, 57 Hz interlaced */ - "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x256, 27 kHz, 47 Hz doublescan */ - "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, - 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP - }, { - /* 640x512, 27 kHz, 47 Hz */ - "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x1024, 27 kHz, 47 Hz interlaced */ - "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, - - /* - * VGA Video Modes - */ - - { - /* 640x480, 31 kHz, 60 Hz (VGA) */ - "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 31 kHz, 70 Hz (VGA) */ - "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, - FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, + /* + * AmigaOS Video Modes + * + * If you change these, make sure to update DEFMODE_* as well! + */ + + { + /* 640x200, 15 kHz, 60 Hz (NTSC) */ + "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ + "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 15 kHz, 50 Hz (PAL) */ + "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, + FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ + "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, + FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x480, 29 kHz, 57 Hz */ + "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x960, 29 kHz, 57 Hz interlaced */ + "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, + 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 15 kHz, 72 Hz */ + "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 15 kHz, 72 Hz interlaced */ + "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, + 10, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 29 kHz, 68 Hz */ + "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 29 kHz, 68 Hz interlaced */ + "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, + 16, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 800x300, 23 kHz, 70 Hz */ + "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 800x600, 23 kHz, 70 Hz interlaced */ + "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 27 kHz, 57 Hz doublescan */ + "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x400, 27 kHz, 57 Hz */ + "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x800, 27 kHz, 57 Hz interlaced */ + "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, { + /* 640x256, 27 kHz, 47 Hz doublescan */ + "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, + 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP + }, { + /* 640x512, 27 kHz, 47 Hz */ + "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x1024, 27 kHz, 47 Hz interlaced */ + "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, + 14, + 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP + }, + + /* + * VGA Video Modes + */ + + { + /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 31 kHz, 70 Hz (VGA) */ + "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, + FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, #if 0 - /* - * A2024 video modes - * These modes don't work yet because there's no A2024 driver. - */ - - { - /* 1024x800, 10 Hz */ - "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 1024x800, 15 Hz */ - "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - } + /* + * A2024 video modes + * These modes don't work yet because there's no A2024 driver. + */ + + { + /* 1024x800, 10 Hz */ + "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 1024x800, 15 Hz */ + "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + } #endif }; @@ -953,6 +952,11 @@ static int round_down_bpp = 1; /* for mode probing */ static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ static int amifb_inverse = 0; +static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ +static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ +static u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ +static u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ + /* * Macros for the conversion from real world values to hardware register @@ -992,19 +996,20 @@ static int amifb_inverse = 0; /* bplcon1 (smooth scrolling) */ #define hscroll2hw(hscroll) \ - (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ - ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f)) + (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ + ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ + ((hscroll)>>2 & 0x000f)) /* diwstrt/diwstop/diwhigh (visible display window) */ #define diwstrt2hw(diwstrt_h, diwstrt_v) \ - (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) + (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) #define diwstop2hw(diwstop_h, diwstop_v) \ - (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) + (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ - (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ + (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ - ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) + ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) /* ddfstrt/ddfstop (display DMA) */ @@ -1015,38 +1020,39 @@ static int amifb_inverse = 0; #define hsstrt2hw(hsstrt) (div8(hsstrt)) #define hsstop2hw(hsstop) (div8(hsstop)) -#define htotal2hw(htotal) (div8(htotal)-1) +#define htotal2hw(htotal) (div8(htotal) - 1) #define vsstrt2hw(vsstrt) (div2(vsstrt)) #define vsstop2hw(vsstop) (div2(vsstop)) -#define vtotal2hw(vtotal) (div2(vtotal)-1) +#define vtotal2hw(vtotal) (div2(vtotal) - 1) #define hcenter2hw(htotal) (div8(htotal)) /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ -#define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) -#define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) +#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) +#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) #define vbstrt2hw(vbstrt) (div2(vbstrt)) #define vbstop2hw(vbstop) (div2(vbstop)) /* colour */ #define rgb2hw8_high(red, green, blue) \ - (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) + (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) #define rgb2hw8_low(red, green, blue) \ - (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f)) + (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) #define rgb2hw4(red, green, blue) \ - (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) + (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) #define rgb2hw2(red, green, blue) \ - (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4)) + (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) /* sprpos/sprctl (sprite positioning) */ #define spr2hw_pos(start_v, start_h) \ - (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff)) + (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) #define spr2hw_ctl(start_v, start_h, stop_v) \ - (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \ - ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \ - ((start_h)>>2&0x0001)) + (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ + ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ + ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ + ((start_h)>>2 & 0x0001)) /* get current vertical position of beam */ #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) @@ -1055,7 +1061,7 @@ static int amifb_inverse = 0; * Copper Initialisation List */ -#define COPINITSIZE (sizeof(copins)*40) +#define COPINITSIZE (sizeof(copins) * 40) enum { cip_bplcon0 @@ -1066,7 +1072,7 @@ enum { * Don't change the order, build_copper()/rebuild_copper() rely on this */ -#define COPLISTSIZE (sizeof(copins)*64) +#define COPLISTSIZE (sizeof(copins) * 64) enum { cop_wait, cop_bplcon0, @@ -1108,82 +1114,1199 @@ static u_short sprfetchmode[3] = { }; +/* --------------------------- Hardware routines --------------------------- */ + /* - * Interface used by the world + * Get the video params out of `var'. If a value doesn't fit, round + * it up, if it's too big, return -EINVAL. */ -int amifb_setup(char*); +static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, + const struct fb_info *info) +{ + u_short clk_shift, line_shift; + u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; + u_int htotal, vtotal; -static int amifb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info); -static int amifb_set_par(struct fb_info *info); -static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info); -static int amifb_blank(int blank, struct fb_info *info); -static int amifb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info); -static void amifb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect); -static void amifb_copyarea(struct fb_info *info, - const struct fb_copyarea *region); -static void amifb_imageblit(struct fb_info *info, - const struct fb_image *image); -static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); + /* + * Find a matching Pixel Clock + */ + for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) + if (var->pixclock <= pixclock[clk_shift]) + break; + if (clk_shift > TAG_LORES) { + DPRINTK("pixclock too high\n"); + return -EINVAL; + } + par->clk_shift = clk_shift; /* - * Interface to the low level console driver + * Check the Geometry Values */ -static void amifb_deinit(struct platform_device *pdev); + if ((par->xres = var->xres) < 64) + par->xres = 64; + if ((par->yres = var->yres) < 64) + par->yres = 64; + if ((par->vxres = var->xres_virtual) < par->xres) + par->vxres = par->xres; + if ((par->vyres = var->yres_virtual) < par->yres) + par->vyres = par->yres; + + par->bpp = var->bits_per_pixel; + if (!var->nonstd) { + if (par->bpp < 1) + par->bpp = 1; + if (par->bpp > maxdepth[clk_shift]) { + if (round_down_bpp && maxdepth[clk_shift]) + par->bpp = maxdepth[clk_shift]; + else { + DPRINTK("invalid bpp\n"); + return -EINVAL; + } + } + } else if (var->nonstd == FB_NONSTD_HAM) { + if (par->bpp < 6) + par->bpp = 6; + if (par->bpp != 6) { + if (par->bpp < 8) + par->bpp = 8; + if (par->bpp != 8 || !IS_AGA) { + DPRINTK("invalid bpp for ham mode\n"); + return -EINVAL; + } + } + } else { + DPRINTK("unknown nonstd mode\n"); + return -EINVAL; + } /* - * Internal routines + * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing + * checks failed and smooth scrolling is not possible */ -static int flash_cursor(void); -static irqreturn_t amifb_interrupt(int irq, void *dev_id); -static u_long chipalloc(u_long size); -static void chipfree(void); + par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + line_shift = 0; + break; + case FB_VMODE_NONINTERLACED: + line_shift = 1; + break; + case FB_VMODE_DOUBLE: + if (!IS_AGA) { + DPRINTK("double mode only possible with aga\n"); + return -EINVAL; + } + line_shift = 2; + break; + default: + DPRINTK("unknown video mode\n"); + return -EINVAL; + break; + } + par->line_shift = line_shift; /* - * Hardware routines + * Vertical and Horizontal Timings */ -static int ami_decode_var(struct fb_var_screeninfo *var, - struct amifb_par *par); -static int ami_encode_var(struct fb_var_screeninfo *var, - struct amifb_par *par); -static void ami_pan_var(struct fb_var_screeninfo *var); -static int ami_update_par(void); -static void ami_update_display(void); -static void ami_init_display(void); -static void ami_do_blank(void); -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix); -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data); -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data); -static int ami_get_cursorstate(struct fb_cursorstate *state); -static int ami_set_cursorstate(struct fb_cursorstate *state); -static void ami_set_sprite(void); -static void ami_init_copper(void); -static void ami_reinit_copper(void); -static void ami_build_copper(void); -static void ami_rebuild_copper(void); + xres_n = par->xres << clk_shift; + yres_n = par->yres << line_shift; + par->htotal = down8((var->left_margin + par->xres + var->right_margin + + var->hsync_len) << clk_shift); + par->vtotal = + down2(((var->upper_margin + par->yres + var->lower_margin + + var->vsync_len) << line_shift) + 1); + if (IS_AGA) + par->bplcon3 = sprpixmode[clk_shift]; + else + par->bplcon3 = 0; + if (var->sync & FB_SYNC_BROADCAST) { + par->diwstop_h = par->htotal - + ((var->right_margin - var->hsync_len) << clk_shift); + if (IS_AGA) + par->diwstop_h += mod4(var->hsync_len); + else + par->diwstop_h = down4(par->diwstop_h); + + par->diwstrt_h = par->diwstop_h - xres_n; + par->diwstop_v = par->vtotal - + ((var->lower_margin - var->vsync_len) << line_shift); + par->diwstrt_v = par->diwstop_v - yres_n; + if (par->diwstop_h >= par->htotal + 8) { + DPRINTK("invalid diwstop_h\n"); + return -EINVAL; + } + if (par->diwstop_v > par->vtotal) { + DPRINTK("invalid diwstop_v\n"); + return -EINVAL; + } + + if (!IS_OCS) { + /* Initialize sync with some reasonable values for pwrsave */ + par->hsstrt = 160; + par->hsstop = 320; + par->vsstrt = 30; + par->vsstop = 34; + } else { + par->hsstrt = 0; + par->hsstop = 0; + par->vsstrt = 0; + par->vsstop = 0; + } + if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { + /* PAL video mode */ + if (par->htotal != PAL_HTOTAL) { + DPRINTK("htotal invalid for pal\n"); + return -EINVAL; + } + if (par->diwstrt_h < PAL_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for pal\n"); + return -EINVAL; + } + if (par->diwstrt_v < PAL_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for pal\n"); + return -EINVAL; + } + htotal = PAL_HTOTAL>>clk_shift; + vtotal = PAL_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = BMC0_PAL; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = BMC0_PAL; + par->hsstop = 1; + } else if (amiga_vblank != 50) { + DPRINTK("pal not supported by this chipset\n"); + return -EINVAL; + } + } else { + /* NTSC video mode + * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK + * and NTSC activated, so than better let diwstop_h <= 1812 + */ + if (par->htotal != NTSC_HTOTAL) { + DPRINTK("htotal invalid for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_h < NTSC_DIWSTRT_H) { + DPRINTK("diwstrt_h too low for ntsc\n"); + return -EINVAL; + } + if (par->diwstrt_v < NTSC_DIWSTRT_V) { + DPRINTK("diwstrt_v too low for ntsc\n"); + return -EINVAL; + } + htotal = NTSC_HTOTAL>>clk_shift; + vtotal = NTSC_VTOTAL>>1; + if (!IS_OCS) { + par->beamcon0 = 0; + par->bplcon3 |= BPC3_BRDRBLNK; + } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || + AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { + par->beamcon0 = 0; + par->hsstop = 1; + } else if (amiga_vblank != 60) { + DPRINTK("ntsc not supported by this chipset\n"); + return -EINVAL; + } + } + if (IS_OCS) { + if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || + par->diwstrt_v >= 512 || par->diwstop_v < 256) { + DPRINTK("invalid position for display on ocs\n"); + return -EINVAL; + } + } + } else if (!IS_OCS) { + /* Programmable video mode */ + par->hsstrt = var->right_margin << clk_shift; + par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; + par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); + if (!IS_AGA) + par->diwstop_h = down4(par->diwstop_h) - 16; + par->diwstrt_h = par->diwstop_h - xres_n; + par->hbstop = par->diwstrt_h + 4; + par->hbstrt = par->diwstop_h + 4; + if (par->hbstrt >= par->htotal + 8) + par->hbstrt -= par->htotal; + par->hcenter = par->hsstrt + (par->htotal >> 1); + par->vsstrt = var->lower_margin << line_shift; + par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; + par->diwstop_v = par->vtotal; + if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + par->diwstop_v -= 2; + par->diwstrt_v = par->diwstop_v - yres_n; + par->vbstop = par->diwstrt_v - 2; + par->vbstrt = par->diwstop_v - 2; + if (par->vtotal > 2048) { + DPRINTK("vtotal too high\n"); + return -EINVAL; + } + if (par->htotal > 2048) { + DPRINTK("htotal too high\n"); + return -EINVAL; + } + par->bplcon3 |= BPC3_EXTBLKEN; + par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | + BMC0_PAL | BMC0_VARCSYEN; + if (var->sync & FB_SYNC_HOR_HIGH_ACT) + par->beamcon0 |= BMC0_HSYTRUE; + if (var->sync & FB_SYNC_VERT_HIGH_ACT) + par->beamcon0 |= BMC0_VSYTRUE; + if (var->sync & FB_SYNC_COMP_HIGH_ACT) + par->beamcon0 |= BMC0_CSYTRUE; + htotal = par->htotal>>clk_shift; + vtotal = par->vtotal>>1; + } else { + DPRINTK("only broadcast modes possible for ocs\n"); + return -EINVAL; + } + + /* + * Checking the DMA timing + */ + + fconst = 16 << maxfmode << clk_shift; + + /* + * smallest window start value without turn off other dma cycles + * than sprite1-7, unless you change min_fstrt + */ + + + fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); + fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; + if (fstrt < min_fstrt) { + DPRINTK("fetch start too low\n"); + return -EINVAL; + } + + /* + * smallest window start value where smooth scrolling is possible + */ + + fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - + fsize; + if (fstrt < min_fstrt) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + maxfetchstop = down16(par->htotal - 80); + + fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; + fsize = upx(fconst, xres_n + + modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); + if (fstrt + fsize > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = upx(fconst, xres_n); + if (fstrt + fsize > maxfetchstop) { + DPRINTK("fetch stop too high\n"); + return -EINVAL; + } + + if (maxfmode + clk_shift <= 1) { + fsize = up64(xres_n + fconst - 1); + if (min_fstrt + fsize - 64 > maxfetchstop) + par->vmode &= ~FB_VMODE_SMOOTH_XPAN; + + fsize = up64(xres_n); + if (min_fstrt + fsize - 64 > maxfetchstop) { + DPRINTK("fetch size too high\n"); + return -EINVAL; + } + + fsize -= 64; + } else + fsize -= fconst; + + /* + * Check if there is enough time to update the bitplane pointers for ywrap + */ + + if (par->htotal - fsize - 64 < par->bpp * 64) + par->vmode &= ~FB_VMODE_YWRAP; + + /* + * Bitplane calculations and check the Memory Requirements + */ + + if (amifb_ilbm) { + par->next_plane = div8(upx(16 << maxfmode, par->vxres)); + par->next_line = par->bpp * par->next_plane; + if (par->next_line * par->vyres > info->fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } else { + par->next_line = div8(upx(16 << maxfmode, par->vxres)); + par->next_plane = par->vyres * par->next_line; + if (par->next_plane * par->bpp > info->fix.smem_len) { + DPRINTK("too few video mem\n"); + return -EINVAL; + } + } + + /* + * Hardware Register Values + */ + + par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; + if (!IS_OCS) + par->bplcon0 |= BPC0_ECSENA; + if (par->bpp == 8) + par->bplcon0 |= BPC0_BPU3; + else + par->bplcon0 |= par->bpp << 12; + if (var->nonstd == FB_NONSTD_HAM) + par->bplcon0 |= BPC0_HAM; + if (var->sync & FB_SYNC_EXT) + par->bplcon0 |= BPC0_ERSY; + + if (IS_AGA) + par->fmode = bplfetchmode[maxfmode]; + + switch (par->vmode & FB_VMODE_MASK) { + case FB_VMODE_INTERLACED: + par->bplcon0 |= BPC0_LACE; + break; + case FB_VMODE_DOUBLE: + if (IS_AGA) + par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; + break; + } + + if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->xoffset || par->yoffset < 0 || + par->yoffset >= par->vyres) + par->xoffset = par->yoffset = 0; + } else { + if (par->xoffset < 0 || + par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || + par->yoffset < 0 || par->yoffset > par->vyres - par->yres) + par->xoffset = par->yoffset = 0; + } + } else + par->xoffset = par->yoffset = 0; + + par->crsr.crsr_x = par->crsr.crsr_y = 0; + par->crsr.spot_x = par->crsr.spot_y = 0; + par->crsr.height = par->crsr.width = 0; + + return 0; +} + + /* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static void ami_encode_var(struct fb_var_screeninfo *var, + struct amifb_par *par) +{ + u_short clk_shift, line_shift; + + memset(var, 0, sizeof(struct fb_var_screeninfo)); + + clk_shift = par->clk_shift; + line_shift = par->line_shift; + + var->xres = par->xres; + var->yres = par->yres; + var->xres_virtual = par->vxres; + var->yres_virtual = par->vyres; + var->xoffset = par->xoffset; + var->yoffset = par->yoffset; + + var->bits_per_pixel = par->bpp; + var->grayscale = 0; + + var->red.offset = 0; + var->red.msb_right = 0; + var->red.length = par->bpp; + if (par->bplcon0 & BPC0_HAM) + var->red.length -= 2; + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + + if (par->bplcon0 & BPC0_HAM) + var->nonstd = FB_NONSTD_HAM; + else + var->nonstd = 0; + var->activate = 0; + + var->height = -1; + var->width = -1; + + var->pixclock = pixclock[clk_shift]; + + if (IS_AGA && par->fmode & FMODE_BSCAN2) + var->vmode = FB_VMODE_DOUBLE; + else if (par->bplcon0 & BPC0_LACE) + var->vmode = FB_VMODE_INTERLACED; + else + var->vmode = FB_VMODE_NONINTERLACED; + + if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { + var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; + var->right_margin = par->hsstrt>>clk_shift; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; + var->lower_margin = par->vsstrt>>line_shift; + var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; + var->sync = 0; + if (par->beamcon0 & BMC0_HSYTRUE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (par->beamcon0 & BMC0_VSYTRUE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + if (par->beamcon0 & BMC0_CSYTRUE) + var->sync |= FB_SYNC_COMP_HIGH_ACT; + } else { + var->sync = FB_SYNC_BROADCAST; + var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); + var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; + var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; + var->vsync_len = 4>>line_shift; + var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; + var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - + var->lower_margin - var->vsync_len; + } + + if (par->bplcon0 & BPC0_ERSY) + var->sync |= FB_SYNC_EXT; + if (par->vmode & FB_VMODE_YWRAP) + var->vmode |= FB_VMODE_YWRAP; +} + + + /* + * Update hardware + */ + +static void ami_update_par(struct fb_info *info) +{ + struct amifb_par *par = info->par; + short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; + + clk_shift = par->clk_shift; + + if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) + par->xoffset = upx(16 << maxfmode, par->xoffset); + + fconst = 16 << maxfmode << clk_shift; + vshift = modx(16 << maxfmode, par->xoffset); + fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; + fsize = (par->xres + vshift) << clk_shift; + shift = modx(fconst, fstrt); + move = downx(2 << maxfmode, div8(par->xoffset)); + if (maxfmode + clk_shift > 1) { + fstrt = downx(fconst, fstrt) - 64; + fsize = upx(fconst, fsize); + fstop = fstrt + fsize - fconst; + } else { + mod = fstrt = downx(fconst, fstrt) - fconst; + fstop = fstrt + upx(fconst, fsize) - 64; + fsize = up64(fsize); + fstrt = fstop - fsize + 64; + if (fstrt < min_fstrt) { + fstop += min_fstrt - fstrt; + fstrt = min_fstrt; + } + move = move - div8((mod - fstrt)>>clk_shift); + } + mod = par->next_line - div8(fsize>>clk_shift); + par->ddfstrt = fstrt; + par->ddfstop = fstop; + par->bplcon1 = hscroll2hw(shift); + par->bpl2mod = mod; + if (par->bplcon0 & BPC0_LACE) + par->bpl2mod += par->next_line; + if (IS_AGA && (par->fmode & FMODE_BSCAN2)) + par->bpl1mod = -div8(fsize>>clk_shift); + else + par->bpl1mod = par->bpl2mod; + + if (par->yoffset) { + par->bplpt0 = info->fix.smem_start + + par->next_line * par->yoffset + move; + if (par->vmode & FB_VMODE_YWRAP) { + if (par->yoffset > par->vyres - par->yres) { + par->bplpt0wrap = info->fix.smem_start + move; + if (par->bplcon0 & BPC0_LACE && + mod2(par->diwstrt_v + par->vyres - + par->yoffset)) + par->bplpt0wrap += par->next_line; + } + } + } else + par->bplpt0 = info->fix.smem_start + move; + + if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) + par->bplpt0 += par->next_line; +} + + + /* + * Pan or Wrap the Display + * + * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag + * in `var'. + */ + +static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct amifb_par *par = info->par; + + par->xoffset = var->xoffset; + par->yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + par->vmode |= FB_VMODE_YWRAP; + else + par->vmode &= ~FB_VMODE_YWRAP; + + do_vmode_pan = 0; + ami_update_par(info); + do_vmode_pan = 1; +} + + +static void ami_update_display(const struct amifb_par *par) +{ + custom.bplcon1 = par->bplcon1; + custom.bpl1mod = par->bpl1mod; + custom.bpl2mod = par->bpl2mod; + custom.ddfstrt = ddfstrt2hw(par->ddfstrt); + custom.ddfstop = ddfstop2hw(par->ddfstop); +} + + /* + * Change the video mode (called by VBlank interrupt) + */ + +static void ami_init_display(const struct amifb_par *par) +{ + int i; + + custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; + custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; + if (!IS_OCS) { + custom.bplcon3 = par->bplcon3; + if (IS_AGA) + custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; + if (par->beamcon0 & BMC0_VARBEAMEN) { + custom.htotal = htotal2hw(par->htotal); + custom.hbstrt = hbstrt2hw(par->hbstrt); + custom.hbstop = hbstop2hw(par->hbstop); + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.hcenter = hcenter2hw(par->hcenter); + custom.vtotal = vtotal2hw(par->vtotal); + custom.vbstrt = vbstrt2hw(par->vbstrt); + custom.vbstop = vbstop2hw(par->vbstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + } + } + if (!IS_OCS || par->hsstop) + custom.beamcon0 = par->beamcon0; + if (IS_AGA) + custom.fmode = par->fmode; + + /* + * The minimum period for audio depends on htotal + */ + + amiga_audio_min_period = div16(par->htotal); + + is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; +#if 1 + if (is_lace) { + i = custom.vposr >> 15; + } else { + custom.vposw = custom.vposr | 0x8000; + i = 1; + } +#else + i = 1; + custom.vposw = custom.vposr | 0x8000; +#endif + custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); +} + + /* + * (Un)Blank the screen (called by VBlank interrupt) + */ + +static void ami_do_blank(const struct amifb_par *par) +{ +#if defined(CONFIG_FB_AMIGA_AGA) + u_short bplcon3 = par->bplcon3; +#endif + u_char red, green, blue; + + if (do_blank > 0) { + custom.dmacon = DMAF_RASTER | DMAF_SPRITE; + red = green = blue = 0; + if (!IS_OCS && do_blank > 1) { + switch (do_blank) { + case FB_BLANK_VSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vtotal + 4); + custom.vsstop = vsstop2hw(par->vtotal + 4); + break; + case FB_BLANK_HSYNC_SUSPEND: + custom.hsstrt = hsstrt2hw(par->htotal + 16); + custom.hsstop = hsstop2hw(par->htotal + 16); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstrt2hw(par->vsstop); + break; + case FB_BLANK_POWERDOWN: + custom.hsstrt = hsstrt2hw(par->htotal + 16); + custom.hsstop = hsstop2hw(par->htotal + 16); + custom.vsstrt = vsstrt2hw(par->vtotal + 4); + custom.vsstop = vsstop2hw(par->vtotal + 4); + break; + } + if (!(par->beamcon0 & BMC0_VARBEAMEN)) { + custom.htotal = htotal2hw(par->htotal); + custom.vtotal = vtotal2hw(par->vtotal); + custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | + BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; + } + } + } else { + custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; + red = red0; + green = green0; + blue = blue0; + if (!IS_OCS) { + custom.hsstrt = hsstrt2hw(par->hsstrt); + custom.hsstop = hsstop2hw(par->hsstop); + custom.vsstrt = vsstrt2hw(par->vsstrt); + custom.vsstop = vsstop2hw(par->vsstop); + custom.beamcon0 = par->beamcon0; + } + } +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + custom.bplcon3 = bplcon3; + custom.color[0] = rgb2hw8_high(red, green, blue); + custom.bplcon3 = bplcon3 | BPC3_LOCT; + custom.color[0] = rgb2hw8_low(red, green, blue); + custom.bplcon3 = bplcon3; + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + for (i = 12; i >= 0; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<= 2; color >>= 2; + for (i = 3; i >= 0; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + } else +#endif + custom.color[0] = rgb2hw4(red, green, blue); + is_blanked = do_blank > 0 ? do_blank : 0; +} + +static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, + const struct amifb_par *par) +{ + fix->crsr_width = fix->crsr_xsize = par->crsr.width; + fix->crsr_height = fix->crsr_ysize = par->crsr.height; + fix->crsr_color1 = 17; + fix->crsr_color2 = 18; + return 0; +} + +static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, + const struct amifb_par *par) +{ + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + register u_char color; + short height, width, bits, words; + int size, alloc; + + size = par->crsr.height * par->crsr.width; + alloc = var->height * var->width; + var->height = par->crsr.height; + var->width = par->crsr.width; + var->xspot = par->crsr.spot_x; + var->yspot = par->crsr.spot_y; + if (size > var->height * var->width) + return -ENAMETOOLONG; + if (!access_ok(VERIFY_WRITE, data, size)) + return -EFAULT; + delta = 1 << par->crsr.fmode; + lspr = lofsprite + (delta << 1); + if (par->bplcon0 & BPC0_LACE) + sspr = shfsprite + (delta << 1); + else + sspr = NULL; + for (height = (short)var->height - 1; height >= 0; height--) { + bits = 0; words = delta; datawords = 0; + for (width = (short)var->width - 1; width >= 0; width--) { + if (bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" + : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); +#else + datawords = (*(lspr + delta) << 16) | (*lspr++); +#endif + } + --bits; +#ifdef __mc68000__ + asm volatile ( + "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " + "swap %1 ; lslw #1,%1 ; roxlb #1,%0" + : "=d" (color), "=d" (datawords) : "1" (datawords)); +#else + color = (((datawords >> 30) & 2) + | ((datawords >> 15) & 1)); + datawords <<= 1; +#endif + put_user(color, data++); + } + if (bits > 0) { + --words; ++lspr; + } + while (--words >= 0) + ++lspr; +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + return 0; +} + +static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, + u_char __user *data, struct amifb_par *par) +{ + register u_short *lspr, *sspr; +#ifdef __mc68000__ + register u_long datawords asm ("d2"); +#else + register u_long datawords; +#endif + register short delta; + u_short fmode; + short height, width, bits, words; + + if (!var->width) + return -EINVAL; + else if (var->width <= 16) + fmode = TAG_FMODE_1; + else if (var->width <= 32) + fmode = TAG_FMODE_2; + else if (var->width <= 64) + fmode = TAG_FMODE_4; + else + return -EINVAL; + if (fmode > maxfmode) + return -EINVAL; + if (!var->height) + return -EINVAL; + if (!access_ok(VERIFY_READ, data, var->width * var->height)) + return -EFAULT; + delta = 1 << fmode; + lofsprite = shfsprite = (u_short *)spritememory; + lspr = lofsprite + (delta << 1); + if (par->bplcon0 & BPC0_LACE) { + if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height + 4) << fmode << 2); + shfsprite += ((var->height + 5)&-2) << fmode; + sspr = shfsprite + (delta << 1); + } else { + if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) + return -EINVAL; + memset(lspr, 0, (var->height + 2) << fmode << 2); + sspr = NULL; + } + for (height = (short)var->height - 1; height >= 0; height--) { + bits = 16; words = delta; datawords = 0; + for (width = (short)var->width - 1; width >= 0; width--) { + unsigned long tdata = 0; + get_user(tdata, data); + data++; +#ifdef __mc68000__ + asm volatile ( + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " + "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" + : "=d" (datawords) + : "0" (datawords), "d" (tdata)); +#else + datawords = ((datawords << 1) & 0xfffefffe); + datawords |= tdata & 1; + datawords |= (tdata & 2) << (16 - 1); +#endif + if (--bits == 0) { + bits = 16; --words; +#ifdef __mc68000__ + asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); +#else + *(lspr + delta) = (u_short) (datawords >> 16); + *lspr++ = (u_short) (datawords & 0xffff); +#endif + } + } + if (bits < 16) { + --words; +#ifdef __mc68000__ + asm volatile ( + "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " + "swap %2 ; lslw %4,%2 ; movew %2,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); +#else + *(lspr + delta) = (u_short) (datawords >> (16 + bits)); + *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); +#endif + } + while (--words >= 0) { +#ifdef __mc68000__ + asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" + : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); +#else + *(lspr + delta) = 0; + *lspr++ = 0; +#endif + } +#ifdef __mc68000__ + asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" + : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); +#else + lspr += delta; + if (sspr) { + u_short *tmp = lspr; + lspr = sspr; + sspr = tmp; + } +#endif + } + par->crsr.height = var->height; + par->crsr.width = var->width; + par->crsr.spot_x = var->xspot; + par->crsr.spot_y = var->yspot; + par->crsr.fmode = fmode; + if (IS_AGA) { + par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); + par->fmode |= sprfetchmode[fmode]; + custom.fmode = par->fmode; + } + return 0; +} + +static int ami_get_cursorstate(struct fb_cursorstate *state, + const struct amifb_par *par) +{ + state->xoffset = par->crsr.crsr_x; + state->yoffset = par->crsr.crsr_y; + state->mode = cursormode; + return 0; +} + +static int ami_set_cursorstate(struct fb_cursorstate *state, + struct amifb_par *par) +{ + par->crsr.crsr_x = state->xoffset; + par->crsr.crsr_y = state->yoffset; + if ((cursormode = state->mode) == FB_CURSOR_OFF) + cursorstate = -1; + do_cursor = 1; + return 0; +} + +static void ami_set_sprite(const struct amifb_par *par) +{ + copins *copl, *cops; + u_short hs, vs, ve; + u_long pl, ps, pt; + short mx, my; + + cops = copdisplay.list[currentcop][0]; + copl = copdisplay.list[currentcop][1]; + ps = pl = ZTWO_PADDR(dummysprite); + mx = par->crsr.crsr_x - par->crsr.spot_x; + my = par->crsr.crsr_y - par->crsr.spot_y; + if (!(par->vmode & FB_VMODE_YWRAP)) { + mx -= par->xoffset; + my -= par->yoffset; + } + if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && + mx > -(short)par->crsr.width && mx < par->xres && + my > -(short)par->crsr.height && my < par->yres) { + pl = ZTWO_PADDR(lofsprite); + hs = par->diwstrt_h + (mx << par->clk_shift) - 4; + vs = par->diwstrt_v + (my << par->line_shift); + ve = vs + (par->crsr.height << par->line_shift); + if (par->bplcon0 & BPC0_LACE) { + ps = ZTWO_PADDR(shfsprite); + lofsprite[0] = spr2hw_pos(vs, hs); + shfsprite[0] = spr2hw_pos(vs + 1, hs); + if (mod2(vs)) { + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); + pt = pl; pl = ps; ps = pt; + } else { + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); + shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); + } + } else { + lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); + lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); + } + } + copl[cop_spr0ptrh].w[1] = highw(pl); + copl[cop_spr0ptrl].w[1] = loww(pl); + if (par->bplcon0 & BPC0_LACE) { + cops[cop_spr0ptrh].w[1] = highw(ps); + cops[cop_spr0ptrl].w[1] = loww(ps); + } +} + + + /* + * Initialise the Copper Initialisation List + */ + +static void __init ami_init_copper(void) +{ + copins *cop = copdisplay.init; + u_long p; + int i; + + if (!IS_OCS) { + (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); + (cop++)->l = CMOVE(0x0181, diwstrt); + (cop++)->l = CMOVE(0x0281, diwstop); + (cop++)->l = CMOVE(0x0000, diwhigh); + } else + (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); + p = ZTWO_PADDR(dummysprite); + for (i = 0; i < 8; i++) { + (cop++)->l = CMOVE(0, spr[i].pos); + (cop++)->l = CMOVE(highw(p), sprpt[i]); + (cop++)->l = CMOVE2(loww(p), sprpt[i]); + } + + (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); + copdisplay.wait = cop; + (cop++)->l = CEND; + (cop++)->l = CMOVE(0, copjmp2); + cop->l = CEND; + + custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); + custom.copjmp1 = 0; +} + +static void ami_reinit_copper(const struct amifb_par *par) +{ + copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; + copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); +} + + + /* + * Rebuild the Copper List + * + * We only change the things that are not static + */ + +static void ami_rebuild_copper(const struct amifb_par *par) +{ + copins *copl, *cops; + u_short line, h_end1, h_end2; + short i; + u_long p; + + if (IS_AGA && maxfmode + par->clk_shift == 0) + h_end1 = par->diwstrt_h - 64; + else + h_end1 = par->htotal - 32; + h_end2 = par->ddfstop + 64; + + ami_set_sprite(par); + + copl = copdisplay.rebuild[1]; + p = par->bplpt0; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres - par->yres) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; + while (line >= 512) { + (copl++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (copl++)->l = CWAIT(h_end1, line); + else + (copl++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + } + } else + p = par->bplpt0wrap; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (copl++)->l = CMOVE(highw(p), bplpt[i]); + (copl++)->l = CMOVE2(loww(p), bplpt[i]); + } + copl->l = CEND; + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.rebuild[0]; + p = par->bplpt0; + if (mod2(par->diwstrt_v)) + p -= par->next_line; + else + p += par->next_line; + if (par->vmode & FB_VMODE_YWRAP) { + if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { + if (par->yoffset > par->vyres - par->yres + 1) { + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; + while (line >= 512) { + (cops++)->l = CWAIT(h_end1, 510); + line -= 512; + } + if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) + (cops++)->l = CWAIT(h_end1, line); + else + (cops++)->l = CWAIT(h_end2, line); + p = par->bplpt0wrap; + if (mod2(par->diwstrt_v + par->vyres - + par->yoffset)) + p -= par->next_line; + else + p += par->next_line; + } + } else + p = par->bplpt0wrap - par->next_line; + } + for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { + (cops++)->l = CMOVE(highw(p), bplpt[i]); + (cops++)->l = CMOVE2(loww(p), bplpt[i]); + } + cops->l = CEND; + } +} + + + /* + * Build the Copper List + */ + +static void ami_build_copper(struct fb_info *info) +{ + struct amifb_par *par = info->par; + copins *copl, *cops; + u_long p; + + currentcop = 1 - currentcop; + + copl = copdisplay.list[currentcop][1]; + + (copl++)->l = CWAIT(0, 10); + (copl++)->l = CMOVE(par->bplcon0, bplcon0); + (copl++)->l = CMOVE(0, sprpt[0]); + (copl++)->l = CMOVE2(0, sprpt[0]); + + if (par->bplcon0 & BPC0_LACE) { + cops = copdisplay.list[currentcop][0]; + + (cops++)->l = CWAIT(0, 10); + (cops++)->l = CMOVE(par->bplcon0, bplcon0); + (cops++)->l = CMOVE(0, sprpt[0]); + (cops++)->l = CMOVE2(0, sprpt[0]); + + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); + (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, + par->diwstop_h, par->diwstop_v + 1), diwhigh); + (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); + (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + p = ZTWO_PADDR(copdisplay.list[currentcop][0]); + (copl++)->l = CMOVE(highw(p), cop2lc); + (copl++)->l = CMOVE2(loww(p), cop2lc); + p = ZTWO_PADDR(copdisplay.list[currentcop][1]); + (cops++)->l = CMOVE(highw(p), cop2lc); + (cops++)->l = CMOVE2(loww(p), cop2lc); + copdisplay.rebuild[0] = cops; + } else { + (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); + (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); + if (!IS_OCS) { + (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, + par->diwstop_h, par->diwstop_v), diwhigh); +#if 0 + if (par->beamcon0 & BMC0_VARBEAMEN) { + (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); + (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); + (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); + } +#endif + } + } + copdisplay.rebuild[1] = copl; + + ami_update_par(info); + ami_rebuild_copper(info->par); +} -static struct fb_ops amifb_ops = { - .owner = THIS_MODULE, - .fb_check_var = amifb_check_var, - .fb_set_par = amifb_set_par, - .fb_setcolreg = amifb_setcolreg, - .fb_blank = amifb_blank, - .fb_pan_display = amifb_pan_display, - .fb_fillrect = amifb_fillrect, - .fb_copyarea = amifb_copyarea, - .fb_imageblit = amifb_imageblit, - .fb_ioctl = amifb_ioctl, -}; static void __init amifb_setup_mcap(char *spec) { @@ -1216,13 +2339,13 @@ static void __init amifb_setup_mcap(char *spec) if (hmax <= 0 || hmax <= hmin) return; - fb_info.monspecs.vfmin = vmin; - fb_info.monspecs.vfmax = vmax; - fb_info.monspecs.hfmin = hmin; - fb_info.monspecs.hfmax = hmax; + amifb_hfmin = hmin; + amifb_hfmax = hmax; + amifb_vfmin = vmin; + amifb_vfmax = vmax; } -int __init amifb_setup(char *options) +static int __init amifb_setup(char *options) { char *this_opt; @@ -1238,9 +2361,9 @@ int __init amifb_setup(char *options) } else if (!strcmp(this_opt, "ilbm")) amifb_ilbm = 1; else if (!strncmp(this_opt, "monitorcap:", 11)) - amifb_setup_mcap(this_opt+11); + amifb_setup_mcap(this_opt + 11); else if (!strncmp(this_opt, "fstart:", 7)) - min_fstrt = simple_strtoul(this_opt+7, NULL, 0); + min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); else mode_option = this_opt; } @@ -1259,7 +2382,8 @@ static int amifb_check_var(struct fb_var_screeninfo *var, struct amifb_par par; /* Validate wanted screen parameters */ - if ((err = ami_decode_var(var, &par))) + err = ami_decode_var(var, &par, info); + if (err) return err; /* Encode (possibly rounded) screen parameters */ @@ -1270,16 +2394,19 @@ static int amifb_check_var(struct fb_var_screeninfo *var, static int amifb_set_par(struct fb_info *info) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; + int error; do_vmode_pan = 0; do_vmode_full = 0; /* Decode wanted screen parameters */ - ami_decode_var(&info->var, par); + error = ami_decode_var(&info->var, par, info); + if (error) + return error; /* Set new videomode */ - ami_build_copper(); + ami_build_copper(info); /* Set VBlank trigger */ do_vmode_full = 1; @@ -1295,20 +2422,20 @@ static int amifb_set_par(struct fb_info *info) info->fix.type = FB_TYPE_PLANES; info->fix.type_aux = 0; } - info->fix.line_length = div8(upx(16<<maxfmode, par->vxres)); + info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); if (par->vmode & FB_VMODE_YWRAP) { info->fix.ywrapstep = 1; info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | - FBINFO_READS_FAST; /* override SCROLL_REDRAW */ + FBINFO_READS_FAST; /* override SCROLL_REDRAW */ } else { info->fix.ywrapstep = 0; if (par->vmode & FB_VMODE_SMOOTH_XPAN) info->fix.xpanstep = 1; else - info->fix.xpanstep = 16<<maxfmode; + info->fix.xpanstep = 16 << maxfmode; info->fix.ypanstep = 1; info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; } @@ -1317,6 +2444,95 @@ static int amifb_set_par(struct fb_info *info) /* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + const struct amifb_par *par = info->par; + + if (IS_AGA) { + if (regno > 255) + return 1; + } else if (par->bplcon0 & BPC0_SHRES) { + if (regno > 3) + return 1; + } else { + if (regno > 31) + return 1; + } + red >>= 8; + green >>= 8; + blue >>= 8; + if (!regno) { + red0 = red; + green0 = green; + blue0 = blue; + } + + /* + * Update the corresponding Hardware Color Register, unless it's Color + * Register 0 and the screen is blanked. + * + * VBlank is switched off to protect bplcon3 or ecs_palette[] from + * being changed by ami_do_blank() during the VBlank. + */ + + if (regno || !is_blanked) { +#if defined(CONFIG_FB_AMIGA_AGA) + if (IS_AGA) { + u_short bplcon3 = par->bplcon3; + VBlankOff(); + custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); + custom.color[regno & 31] = rgb2hw8_high(red, green, + blue); + custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | + BPC3_LOCT; + custom.color[regno & 31] = rgb2hw8_low(red, green, + blue); + custom.bplcon3 = bplcon3; + VBlankOn(); + } else +#endif +#if defined(CONFIG_FB_AMIGA_ECS) + if (par->bplcon0 & BPC0_SHRES) { + u_short color, mask; + int i; + + mask = 0x3333; + color = rgb2hw2(red, green, blue); + VBlankOff(); + for (i = regno + 12; i >= (int)regno; i -= 4) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + mask <<= 2; color >>= 2; + regno = down16(regno) + mul4(mod4(regno)); + for (i = regno + 3; i >= (int)regno; i--) + custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; + VBlankOn(); + } else +#endif + custom.color[regno] = rgb2hw4(red, green, blue); + } + return 0; +} + + + /* + * Blank the display. + */ + +static int amifb_blank(int blank, struct fb_info *info) +{ + do_blank = blank ? blank : -1; + + return 0; +} + + + /* * Pan or Wrap the Display * * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag @@ -1327,18 +2543,19 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, { if (var->vmode & FB_VMODE_YWRAP) { if (var->yoffset < 0 || - var->yoffset >= info->var.yres_virtual || var->xoffset) - return -EINVAL; + var->yoffset >= info->var.yres_virtual || var->xoffset) + return -EINVAL; } else { /* * TODO: There will be problems when xpan!=1, so some columns * on the right side will never be seen */ - if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) || - var->yoffset+info->var.yres > info->var.yres_virtual) + if (var->xoffset + info->var.xres > + upx(16 << maxfmode, info->var.xres_virtual) || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } - ami_pan_var(var); + ami_pan_var(var, info); info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) @@ -1360,10 +2577,10 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, #endif - /* - * Compose two values, using a bitmask as decision value - * This is equivalent to (a & mask) | (b & ~mask) - */ + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ static inline unsigned long comp(unsigned long a, unsigned long b, unsigned long mask) @@ -1379,29 +2596,29 @@ static inline unsigned long xor(unsigned long a, unsigned long b, } - /* - * Unaligned forward bit copy using 32-bit or 64-bit memory accesses - */ + /* + * Unaligned forward bit copy using 32-bit or 64-bit memory accesses + */ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n) { unsigned long first, last; - int shift = dst_idx-src_idx, left, right; + int shift = dst_idx - src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; - shift = dst_idx-src_idx; + shift = dst_idx - src_idx; first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); if (!shift) { // Same alignment for source and dest - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1413,7 +2630,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, *dst = comp(*src, *dst, first); dst++; src++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1439,17 +2656,17 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, } else { // Different alignment for source and dest - right = shift & (BITS_PER_LONG-1); - left = -shift & (BITS_PER_LONG-1); + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single destination word if (last) first &= last; if (shift > 0) { // Single source word *dst = comp(*src >> right, *dst, first); - } else if (src_idx+n <= BITS_PER_LONG) { + } else if (src_idx + n <= BITS_PER_LONG) { // Single source word *dst = comp(*src << left, *dst, first); } else { @@ -1467,7 +2684,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, // Single source word *dst = comp(d0 >> right, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } else { // 2 source words d1 = *src++; @@ -1475,7 +2692,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, first); d0 = d1; dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1519,40 +2736,40 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, } - /* - * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses - */ + /* + * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses + */ static void bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n) { unsigned long first, last; - int shift = dst_idx-src_idx, left, right; + int shift = dst_idx - src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; - dst += (n-1)/BITS_PER_LONG; - src += (n-1)/BITS_PER_LONG; - if ((n-1) % BITS_PER_LONG) { - dst_idx += (n-1) % BITS_PER_LONG; + dst += (n - 1) / BITS_PER_LONG; + src += (n - 1) / BITS_PER_LONG; + if ((n - 1) % BITS_PER_LONG) { + dst_idx += (n - 1) % BITS_PER_LONG; dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= BITS_PER_LONG-1; - src_idx += (n-1) % BITS_PER_LONG; + dst_idx &= BITS_PER_LONG - 1; + src_idx += (n - 1) % BITS_PER_LONG; src += src_idx >> SHIFT_PER_LONG; - src_idx &= BITS_PER_LONG-1; + src_idx &= BITS_PER_LONG - 1; } - shift = dst_idx-src_idx; - first = ~0UL << (BITS_PER_LONG-1-dst_idx); - last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG))); + shift = dst_idx - src_idx; + first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); + last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); if (!shift) { // Same alignment for source and dest - if ((unsigned long)dst_idx+1 >= n) { + if ((unsigned long)dst_idx + 1 >= n) { // Single word if (last) first &= last; @@ -1564,7 +2781,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, *dst = comp(*src, *dst, first); dst--; src--; - n -= dst_idx+1; + n -= dst_idx + 1; } // Main chunk @@ -1590,17 +2807,17 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, } else { // Different alignment for source and dest - right = shift & (BITS_PER_LONG-1); - left = -shift & (BITS_PER_LONG-1); + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); - if ((unsigned long)dst_idx+1 >= n) { + if ((unsigned long)dst_idx + 1 >= n) { // Single destination word if (last) first &= last; if (shift < 0) { // Single source word *dst = comp(*src << left, *dst, first); - } else if (1+(unsigned long)src_idx >= n) { + } else if (1 + (unsigned long)src_idx >= n) { // Single source word *dst = comp(*src >> right, *dst, first); } else { @@ -1618,7 +2835,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, // Single source word *dst = comp(d0 << left, *dst, first); dst--; - n -= dst_idx+1; + n -= dst_idx + 1; } else { // 2 source words d1 = *src--; @@ -1626,7 +2843,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, first); d0 = d1; dst--; - n -= dst_idx+1; + n -= dst_idx + 1; } // Main chunk @@ -1670,30 +2887,30 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, } - /* - * Unaligned forward inverting bit copy using 32-bit or 64-bit memory - * accesses - */ + /* + * Unaligned forward inverting bit copy using 32-bit or 64-bit memory + * accesses + */ static void bitcpy_not(unsigned long *dst, int dst_idx, const unsigned long *src, int src_idx, u32 n) { unsigned long first, last; - int shift = dst_idx-src_idx, left, right; + int shift = dst_idx - src_idx, left, right; unsigned long d0, d1; int m; if (!n) return; - shift = dst_idx-src_idx; + shift = dst_idx - src_idx; first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); if (!shift) { // Same alignment for source and dest - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1705,7 +2922,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, *dst = comp(~*src, *dst, first); dst++; src++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1731,17 +2948,17 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, } else { // Different alignment for source and dest - right = shift & (BITS_PER_LONG-1); - left = -shift & (BITS_PER_LONG-1); + right = shift & (BITS_PER_LONG - 1); + left = -shift & (BITS_PER_LONG - 1); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single destination word if (last) first &= last; if (shift > 0) { // Single source word *dst = comp(~*src >> right, *dst, first); - } else if (src_idx+n <= BITS_PER_LONG) { + } else if (src_idx + n <= BITS_PER_LONG) { // Single source word *dst = comp(~*src << left, *dst, first); } else { @@ -1759,7 +2976,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, // Single source word *dst = comp(d0 >> right, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } else { // 2 source words d1 = ~*src++; @@ -1767,7 +2984,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, first); d0 = d1; dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1811,9 +3028,9 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, } - /* - * Unaligned 32-bit pattern fill using 32/64-bit memory accesses - */ + /* + * Unaligned 32-bit pattern fill using 32/64-bit memory accesses + */ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) { @@ -1828,9 +3045,9 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) #endif first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1841,7 +3058,7 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) if (first) { *dst = comp(val, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1867,9 +3084,9 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) } - /* - * Unaligned 32-bit pattern xor using 32/64-bit memory accesses - */ + /* + * Unaligned 32-bit pattern xor using 32/64-bit memory accesses + */ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) { @@ -1884,9 +3101,9 @@ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) #endif first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); + last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - if (dst_idx+n <= BITS_PER_LONG) { + if (dst_idx + n <= BITS_PER_LONG) { // Single word if (last) first &= last; @@ -1897,7 +3114,7 @@ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) if (first) { *dst = xor(val, *dst, first); dst++; - n -= BITS_PER_LONG-dst_idx; + n -= BITS_PER_LONG - dst_idx; } // Main chunk @@ -1924,12 +3141,12 @@ static inline void fill_one_line(int bpp, unsigned long next_plane, { while (1) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); if (!--bpp) break; color >>= 1; - dst_idx += next_plane*8; + dst_idx += next_plane * 8; } } @@ -1939,12 +3156,12 @@ static inline void xor_one_line(int bpp, unsigned long next_plane, { while (color) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); if (!--bpp) break; color >>= 1; - dst_idx += next_plane*8; + dst_idx += next_plane * 8; } } @@ -1952,7 +3169,7 @@ static inline void xor_one_line(int bpp, unsigned long next_plane, static void amifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; int dst_idx, x2, y2; unsigned long *dst; u32 width, height; @@ -1972,23 +3189,23 @@ static void amifb_fillrect(struct fb_info *info, height = y2 - rect->dy; dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; - dst_idx += rect->dy*par->next_line*8+rect->dx; + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += rect->dy * par->next_line * 8 + rect->dx; while (height--) { switch (rect->rop) { - case ROP_COPY: + case ROP_COPY: fill_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, width, rect->color); break; - case ROP_XOR: + case ROP_XOR: xor_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, width, rect->color); break; } - dst_idx += par->next_line*8; + dst_idx += par->next_line * 8; } } @@ -1998,14 +3215,14 @@ static inline void copy_one_line(int bpp, unsigned long next_plane, { while (1) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); src += src_idx >> SHIFT_PER_LONG; - src_idx &= (BITS_PER_LONG-1); + src_idx &= (BITS_PER_LONG - 1); bitcpy(dst, dst_idx, src, src_idx, n); if (!--bpp) break; - dst_idx += next_plane*8; - src_idx += next_plane*8; + dst_idx += next_plane * 8; + src_idx += next_plane * 8; } } @@ -2015,14 +3232,14 @@ static inline void copy_one_line_rev(int bpp, unsigned long next_plane, { while (1) { dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); + dst_idx &= (BITS_PER_LONG - 1); src += src_idx >> SHIFT_PER_LONG; - src_idx &= (BITS_PER_LONG-1); + src_idx &= (BITS_PER_LONG - 1); bitcpy_rev(dst, dst_idx, src, src_idx, n); if (!--bpp) break; - dst_idx += next_plane*8; - src_idx += next_plane*8; + dst_idx += next_plane * 8; + src_idx += next_plane * 8; } } @@ -2030,7 +3247,7 @@ static inline void copy_one_line_rev(int bpp, unsigned long next_plane, static void amifb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; int x2, y2; u32 dx, dy, sx, sy, width, height; unsigned long *dst, *src; @@ -2065,16 +3282,16 @@ static void amifb_copyarea(struct fb_info *info, rev_copy = 1; } dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); src = dst; - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; src_idx = dst_idx; - dst_idx += dy*par->next_line*8+dx; - src_idx += sy*par->next_line*8+sx; + dst_idx += dy * par->next_line * 8 + dx; + src_idx += sy * par->next_line * 8 + sx; if (rev_copy) { while (height--) { - dst_idx -= par->next_line*8; - src_idx -= par->next_line*8; + dst_idx -= par->next_line * 8; + src_idx -= par->next_line * 8; copy_one_line_rev(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, src, src_idx, width); @@ -2084,8 +3301,8 @@ static void amifb_copyarea(struct fb_info *info, copy_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, src, src_idx, width); - dst_idx += par->next_line*8; - src_idx += par->next_line*8; + dst_idx += par->next_line * 8; + src_idx += par->next_line * 8; } } } @@ -2095,34 +3312,35 @@ static inline void expand_one_line(int bpp, unsigned long next_plane, unsigned long *dst, int dst_idx, u32 n, const u8 *data, u32 bgcolor, u32 fgcolor) { - const unsigned long *src; - int src_idx; - - while (1) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG-1); - if ((bgcolor ^ fgcolor) & 1) { - src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1)); - src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8; - if (fgcolor & 1) - bitcpy(dst, dst_idx, src, src_idx, n); - else - bitcpy_not(dst, dst_idx, src, src_idx, n); - /* set or clear */ - } else - bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); - if (!--bpp) - break; - bgcolor >>= 1; - fgcolor >>= 1; - dst_idx += next_plane*8; - } + const unsigned long *src; + int src_idx; + + while (1) { + dst += dst_idx >> SHIFT_PER_LONG; + dst_idx &= (BITS_PER_LONG - 1); + if ((bgcolor ^ fgcolor) & 1) { + src = (unsigned long *) + ((unsigned long)data & ~(BYTES_PER_LONG - 1)); + src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; + if (fgcolor & 1) + bitcpy(dst, dst_idx, src, src_idx, n); + else + bitcpy_not(dst, dst_idx, src, src_idx, n); + /* set or clear */ + } else + bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); + if (!--bpp) + break; + bgcolor >>= 1; + fgcolor >>= 1; + dst_idx += next_plane * 8; + } } static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) { - struct amifb_par *par = (struct amifb_par *)info->par; + struct amifb_par *par = info->par; int x2, y2; unsigned long *dst; int dst_idx; @@ -2145,17 +3363,17 @@ static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) if (image->depth == 1) { dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; - dst_idx += dy*par->next_line*8+dx; + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += dy * par->next_line * 8 + dx; src = image->data; - pitch = (image->width+7)/8; + pitch = (image->width + 7) / 8; while (height--) { expand_one_line(info->var.bits_per_pixel, par->next_plane, dst, dst_idx, width, src, image->bg_color, image->fg_color); - dst_idx += par->next_line*8; + dst_idx += par->next_line * 8; src += pitch; } } else { @@ -2182,45 +3400,119 @@ static int amifb_ioctl(struct fb_info *info, int i; switch (cmd) { - case FBIOGET_FCURSORINFO: - i = ami_get_fix_cursorinfo(&crsr.fix); - if (i) - return i; - return copy_to_user(argp, &crsr.fix, - sizeof(crsr.fix)) ? -EFAULT : 0; - - case FBIOGET_VCURSORINFO: - i = ami_get_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data); - if (i) - return i; - return copy_to_user(argp, &crsr.var, - sizeof(crsr.var)) ? -EFAULT : 0; - - case FBIOPUT_VCURSORINFO: - if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) - return -EFAULT; - return ami_set_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data); - - case FBIOGET_CURSORSTATE: - i = ami_get_cursorstate(&crsr.state); - if (i) - return i; - return copy_to_user(argp, &crsr.state, - sizeof(crsr.state)) ? -EFAULT : 0; - - case FBIOPUT_CURSORSTATE: - if (copy_from_user(&crsr.state, argp, - sizeof(crsr.state))) - return -EFAULT; - return ami_set_cursorstate(&crsr.state); + case FBIOGET_FCURSORINFO: + i = ami_get_fix_cursorinfo(&crsr.fix, info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.fix, + sizeof(crsr.fix)) ? -EFAULT : 0; + + case FBIOGET_VCURSORINFO: + i = ami_get_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.var, + sizeof(crsr.var)) ? -EFAULT : 0; + + case FBIOPUT_VCURSORINFO: + if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) + return -EFAULT; + return ami_set_var_cursorinfo(&crsr.var, + ((struct fb_var_cursorinfo __user *)arg)->data, + info->par); + + case FBIOGET_CURSORSTATE: + i = ami_get_cursorstate(&crsr.state, info->par); + if (i) + return i; + return copy_to_user(argp, &crsr.state, + sizeof(crsr.state)) ? -EFAULT : 0; + + case FBIOPUT_CURSORSTATE: + if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) + return -EFAULT; + return ami_set_cursorstate(&crsr.state, info->par); } return -EINVAL; } /* + * Flash the cursor (called by VBlank interrupt) + */ + +static int flash_cursor(void) +{ + static int cursorcount = 1; + + if (cursormode == FB_CURSOR_FLASH) { + if (!--cursorcount) { + cursorstate = -cursorstate; + cursorcount = cursorrate; + if (!is_blanked) + return 1; + } + } + return 0; +} + + /* + * VBlank Display Interrupt + */ + +static irqreturn_t amifb_interrupt(int irq, void *dev_id) +{ + struct amifb_par *par = dev_id; + + if (do_vmode_pan || do_vmode_full) + ami_update_display(par); + + if (do_vmode_full) + ami_init_display(par); + + if (do_vmode_pan) { + flash_cursor(); + ami_rebuild_copper(par); + do_cursor = do_vmode_pan = 0; + } else if (do_cursor) { + flash_cursor(); + ami_set_sprite(par); + do_cursor = 0; + } else { + if (flash_cursor()) + ami_set_sprite(par); + } + + if (do_blank) { + ami_do_blank(par); + do_blank = 0; + } + + if (do_vmode_full) { + ami_reinit_copper(par); + do_vmode_full = 0; + } + return IRQ_HANDLED; +} + + +static struct fb_ops amifb_ops = { + .owner = THIS_MODULE, + .fb_check_var = amifb_check_var, + .fb_set_par = amifb_set_par, + .fb_setcolreg = amifb_setcolreg, + .fb_blank = amifb_blank, + .fb_pan_display = amifb_pan_display, + .fb_fillrect = amifb_fillrect, + .fb_copyarea = amifb_copyarea, + .fb_imageblit = amifb_imageblit, + .fb_ioctl = amifb_ioctl, +}; + + + /* * Allocate, Clear and Align a Block of Chip Memory */ @@ -2250,6 +3542,7 @@ static inline void chipfree(void) static int __init amifb_probe(struct platform_device *pdev) { + struct fb_info *info; int tag, i, err = 0; u_long chipptr; u_int defmode; @@ -2265,71 +3558,80 @@ static int __init amifb_probe(struct platform_device *pdev) #endif custom.dmacon = DMAF_ALL | DMAF_MASTER; + info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); + if (!info) { + dev_err(&pdev->dev, "framebuffer_alloc failed\n"); + return -ENOMEM; + } + + strcpy(info->fix.id, "Amiga "); + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.accel = FB_ACCEL_AMIGABLITT; + switch (amiga_chipset) { #ifdef CONFIG_FB_AMIGA_OCS - case CS_OCS: - strcat(fb_info.fix.id, "OCS"); + case CS_OCS: + strcat(info->fix.id, "OCS"); default_chipset: - chipset = TAG_OCS; - maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ - maxdepth[TAG_HIRES] = 4; - maxdepth[TAG_LORES] = 6; - maxfmode = TAG_FMODE_1; - defmode = amiga_vblank == 50 ? DEFMODE_PAL - : DEFMODE_NTSC; - fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; - break; + chipset = TAG_OCS; + maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; + info->fix.smem_len = VIDEOMEMSIZE_OCS; + break; #endif /* CONFIG_FB_AMIGA_OCS */ #ifdef CONFIG_FB_AMIGA_ECS - case CS_ECS: - strcat(fb_info.fix.id, "ECS"); - chipset = TAG_ECS; - maxdepth[TAG_SHRES] = 2; - maxdepth[TAG_HIRES] = 4; - maxdepth[TAG_LORES] = 6; - maxfmode = TAG_FMODE_1; - if (AMIGAHW_PRESENT(AMBER_FF)) - defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL - : DEFMODE_AMBER_NTSC; - else - defmode = amiga_vblank == 50 ? DEFMODE_PAL - : DEFMODE_NTSC; - if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > - VIDEOMEMSIZE_ECS_2M) - fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; - else - fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; - break; + case CS_ECS: + strcat(info->fix.id, "ECS"); + chipset = TAG_ECS; + maxdepth[TAG_SHRES] = 2; + maxdepth[TAG_HIRES] = 4; + maxdepth[TAG_LORES] = 6; + maxfmode = TAG_FMODE_1; + if (AMIGAHW_PRESENT(AMBER_FF)) + defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL + : DEFMODE_AMBER_NTSC; + else + defmode = amiga_vblank == 50 ? DEFMODE_PAL + : DEFMODE_NTSC; + if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_ECS_2M) + info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; + else + info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; + break; #endif /* CONFIG_FB_AMIGA_ECS */ #ifdef CONFIG_FB_AMIGA_AGA - case CS_AGA: - strcat(fb_info.fix.id, "AGA"); - chipset = TAG_AGA; - maxdepth[TAG_SHRES] = 8; - maxdepth[TAG_HIRES] = 8; - maxdepth[TAG_LORES] = 8; - maxfmode = TAG_FMODE_4; - defmode = DEFMODE_AGA; - if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > - VIDEOMEMSIZE_AGA_2M) - fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; - else - fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; - break; + case CS_AGA: + strcat(info->fix.id, "AGA"); + chipset = TAG_AGA; + maxdepth[TAG_SHRES] = 8; + maxdepth[TAG_HIRES] = 8; + maxdepth[TAG_LORES] = 8; + maxfmode = TAG_FMODE_4; + defmode = DEFMODE_AGA; + if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > + VIDEOMEMSIZE_AGA_2M) + info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; + else + info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; + break; #endif /* CONFIG_FB_AMIGA_AGA */ - default: + default: #ifdef CONFIG_FB_AMIGA_OCS - printk("Unknown graphics chipset, defaulting to OCS\n"); - strcat(fb_info.fix.id, "Unknown"); - goto default_chipset; + printk("Unknown graphics chipset, defaulting to OCS\n"); + strcat(info->fix.id, "Unknown"); + goto default_chipset; #else /* CONFIG_FB_AMIGA_OCS */ - err = -ENODEV; - goto amifb_error; + err = -ENODEV; + goto release; #endif /* CONFIG_FB_AMIGA_OCS */ - break; + break; } /* @@ -2356,42 +3658,44 @@ default_chipset: } } - /* - * These monitor specs are for a typical Amiga monitor (e.g. A1960) - */ - if (fb_info.monspecs.hfmin == 0) { - fb_info.monspecs.hfmin = 15000; - fb_info.monspecs.hfmax = 38000; - fb_info.monspecs.vfmin = 49; - fb_info.monspecs.vfmax = 90; + if (amifb_hfmin) { + info->monspecs.hfmin = amifb_hfmin; + info->monspecs.hfmax = amifb_hfmax; + info->monspecs.vfmin = amifb_vfmin; + info->monspecs.vfmax = amifb_vfmax; + } else { + /* + * These are for a typical Amiga monitor (e.g. A1960) + */ + info->monspecs.hfmin = 15000; + info->monspecs.hfmax = 38000; + info->monspecs.vfmin = 49; + info->monspecs.vfmax = 90; } - fb_info.fbops = &amifb_ops; - fb_info.par = ¤tpar; - fb_info.flags = FBINFO_DEFAULT; - fb_info.device = &pdev->dev; + info->fbops = &amifb_ops; + info->flags = FBINFO_DEFAULT; + info->device = &pdev->dev; - if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, + if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { err = -EINVAL; - goto amifb_error; + goto release; } fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, - &fb_info.modelist); + &info->modelist); round_down_bpp = 0; - chipptr = chipalloc(fb_info.fix.smem_len+ - SPRITEMEMSIZE+ - DUMMYSPRITEMEMSIZE+ - COPINITSIZE+ - 4*COPLISTSIZE); + chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + + DUMMYSPRITEMEMSIZE + COPINITSIZE + + 4 * COPLISTSIZE); if (!chipptr) { err = -ENOMEM; - goto amifb_error; + goto release; } - assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); + assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); @@ -2403,1398 +3707,78 @@ default_chipset: /* * access the videomem with writethrough cache */ - fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); - videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, - fb_info.fix.smem_len); + info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); + videomemory = (u_long)ioremap_writethrough(info->fix.smem_start, + info->fix.smem_len); if (!videomemory) { - printk("amifb: WARNING! unable to map videomem cached writethrough\n"); - fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start); + dev_warn(&pdev->dev, + "Unable to map videomem cached writethrough\n"); + info->screen_base = (char *)ZTWO_VADDR(info->fix.smem_start); } else - fb_info.screen_base = (char *)videomemory; + info->screen_base = (char *)videomemory; memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); /* - * Enable Display DMA - */ - - custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | - DMAF_BLITTER | DMAF_SPRITE; - - /* * Make sure the Copper has something to do */ - ami_init_copper(); - if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, - "fb vertb handler", ¤tpar)) { - err = -EBUSY; - goto amifb_error; - } - - err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); - if (err) - goto amifb_error; - - if (register_framebuffer(&fb_info) < 0) { - err = -EINVAL; - goto amifb_error; - } - - printk("fb%d: %s frame buffer device, using %dK of video memory\n", - fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10); - - return 0; - -amifb_error: - amifb_deinit(pdev); - return err; -} - -static void amifb_deinit(struct platform_device *pdev) -{ - if (fb_info.cmap.len) - fb_dealloc_cmap(&fb_info.cmap); - fb_dealloc_cmap(&fb_info.cmap); - chipfree(); - if (videomemory) - iounmap((void*)videomemory); - custom.dmacon = DMAF_ALL | DMAF_MASTER; -} - - - /* - * Blank the display. - */ - -static int amifb_blank(int blank, struct fb_info *info) -{ - do_blank = blank ? blank : -1; - - return 0; -} - - /* - * Flash the cursor (called by VBlank interrupt) - */ - -static int flash_cursor(void) -{ - static int cursorcount = 1; - - if (cursormode == FB_CURSOR_FLASH) { - if (!--cursorcount) { - cursorstate = -cursorstate; - cursorcount = cursorrate; - if (!is_blanked) - return 1; - } - } - return 0; -} - - /* - * VBlank Display Interrupt - */ - -static irqreturn_t amifb_interrupt(int irq, void *dev_id) -{ - if (do_vmode_pan || do_vmode_full) - ami_update_display(); - - if (do_vmode_full) - ami_init_display(); - - if (do_vmode_pan) { - flash_cursor(); - ami_rebuild_copper(); - do_cursor = do_vmode_pan = 0; - } else if (do_cursor) { - flash_cursor(); - ami_set_sprite(); - do_cursor = 0; - } else { - if (flash_cursor()) - ami_set_sprite(); - } - - if (do_blank) { - ami_do_blank(); - do_blank = 0; - } - - if (do_vmode_full) { - ami_reinit_copper(); - do_vmode_full = 0; - } - return IRQ_HANDLED; -} - -/* --------------------------- Hardware routines --------------------------- */ - - /* - * Get the video params out of `var'. If a value doesn't fit, round - * it up, if it's too big, return -EINVAL. - */ - -static int ami_decode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) -{ - u_short clk_shift, line_shift; - u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; - u_int htotal, vtotal; - - /* - * Find a matching Pixel Clock - */ - - for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) - if (var->pixclock <= pixclock[clk_shift]) - break; - if (clk_shift > TAG_LORES) { - DPRINTK("pixclock too high\n"); - return -EINVAL; - } - par->clk_shift = clk_shift; - - /* - * Check the Geometry Values - */ - - if ((par->xres = var->xres) < 64) - par->xres = 64; - if ((par->yres = var->yres) < 64) - par->yres = 64; - if ((par->vxres = var->xres_virtual) < par->xres) - par->vxres = par->xres; - if ((par->vyres = var->yres_virtual) < par->yres) - par->vyres = par->yres; - - par->bpp = var->bits_per_pixel; - if (!var->nonstd) { - if (par->bpp < 1) - par->bpp = 1; - if (par->bpp > maxdepth[clk_shift]) { - if (round_down_bpp && maxdepth[clk_shift]) - par->bpp = maxdepth[clk_shift]; - else { - DPRINTK("invalid bpp\n"); - return -EINVAL; - } - } - } else if (var->nonstd == FB_NONSTD_HAM) { - if (par->bpp < 6) - par->bpp = 6; - if (par->bpp != 6) { - if (par->bpp < 8) - par->bpp = 8; - if (par->bpp != 8 || !IS_AGA) { - DPRINTK("invalid bpp for ham mode\n"); - return -EINVAL; - } - } - } else { - DPRINTK("unknown nonstd mode\n"); - return -EINVAL; - } - - /* - * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing - * checks failed and smooth scrolling is not possible - */ - - par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; - switch (par->vmode & FB_VMODE_MASK) { - case FB_VMODE_INTERLACED: - line_shift = 0; - break; - case FB_VMODE_NONINTERLACED: - line_shift = 1; - break; - case FB_VMODE_DOUBLE: - if (!IS_AGA) { - DPRINTK("double mode only possible with aga\n"); - return -EINVAL; - } - line_shift = 2; - break; - default: - DPRINTK("unknown video mode\n"); - return -EINVAL; - break; - } - par->line_shift = line_shift; - - /* - * Vertical and Horizontal Timings - */ - - xres_n = par->xres<<clk_shift; - yres_n = par->yres<<line_shift; - par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift); - par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1); - - if (IS_AGA) - par->bplcon3 = sprpixmode[clk_shift]; - else - par->bplcon3 = 0; - if (var->sync & FB_SYNC_BROADCAST) { - par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift); - if (IS_AGA) - par->diwstop_h += mod4(var->hsync_len); - else - par->diwstop_h = down4(par->diwstop_h); - - par->diwstrt_h = par->diwstop_h - xres_n; - par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift); - par->diwstrt_v = par->diwstop_v - yres_n; - if (par->diwstop_h >= par->htotal+8) { - DPRINTK("invalid diwstop_h\n"); - return -EINVAL; - } - if (par->diwstop_v > par->vtotal) { - DPRINTK("invalid diwstop_v\n"); - return -EINVAL; - } - - if (!IS_OCS) { - /* Initialize sync with some reasonable values for pwrsave */ - par->hsstrt = 160; - par->hsstop = 320; - par->vsstrt = 30; - par->vsstop = 34; - } else { - par->hsstrt = 0; - par->hsstop = 0; - par->vsstrt = 0; - par->vsstop = 0; - } - if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) { - /* PAL video mode */ - if (par->htotal != PAL_HTOTAL) { - DPRINTK("htotal invalid for pal\n"); - return -EINVAL; - } - if (par->diwstrt_h < PAL_DIWSTRT_H) { - DPRINTK("diwstrt_h too low for pal\n"); - return -EINVAL; - } - if (par->diwstrt_v < PAL_DIWSTRT_V) { - DPRINTK("diwstrt_v too low for pal\n"); - return -EINVAL; - } - htotal = PAL_HTOTAL>>clk_shift; - vtotal = PAL_VTOTAL>>1; - if (!IS_OCS) { - par->beamcon0 = BMC0_PAL; - par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || - AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { - par->beamcon0 = BMC0_PAL; - par->hsstop = 1; - } else if (amiga_vblank != 50) { - DPRINTK("pal not supported by this chipset\n"); - return -EINVAL; - } - } else { - /* NTSC video mode - * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK - * and NTSC activated, so than better let diwstop_h <= 1812 - */ - if (par->htotal != NTSC_HTOTAL) { - DPRINTK("htotal invalid for ntsc\n"); - return -EINVAL; - } - if (par->diwstrt_h < NTSC_DIWSTRT_H) { - DPRINTK("diwstrt_h too low for ntsc\n"); - return -EINVAL; - } - if (par->diwstrt_v < NTSC_DIWSTRT_V) { - DPRINTK("diwstrt_v too low for ntsc\n"); - return -EINVAL; - } - htotal = NTSC_HTOTAL>>clk_shift; - vtotal = NTSC_VTOTAL>>1; - if (!IS_OCS) { - par->beamcon0 = 0; - par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || - AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { - par->beamcon0 = 0; - par->hsstop = 1; - } else if (amiga_vblank != 60) { - DPRINTK("ntsc not supported by this chipset\n"); - return -EINVAL; - } - } - if (IS_OCS) { - if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || - par->diwstrt_v >= 512 || par->diwstop_v < 256) { - DPRINTK("invalid position for display on ocs\n"); - return -EINVAL; - } - } - } else if (!IS_OCS) { - /* Programmable video mode */ - par->hsstrt = var->right_margin<<clk_shift; - par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift; - par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); - if (!IS_AGA) - par->diwstop_h = down4(par->diwstop_h) - 16; - par->diwstrt_h = par->diwstop_h - xres_n; - par->hbstop = par->diwstrt_h + 4; - par->hbstrt = par->diwstop_h + 4; - if (par->hbstrt >= par->htotal + 8) - par->hbstrt -= par->htotal; - par->hcenter = par->hsstrt + (par->htotal >> 1); - par->vsstrt = var->lower_margin<<line_shift; - par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift; - par->diwstop_v = par->vtotal; - if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) - par->diwstop_v -= 2; - par->diwstrt_v = par->diwstop_v - yres_n; - par->vbstop = par->diwstrt_v - 2; - par->vbstrt = par->diwstop_v - 2; - if (par->vtotal > 2048) { - DPRINTK("vtotal too high\n"); - return -EINVAL; - } - if (par->htotal > 2048) { - DPRINTK("htotal too high\n"); - return -EINVAL; - } - par->bplcon3 |= BPC3_EXTBLKEN; - par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | - BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | - BMC0_PAL | BMC0_VARCSYEN; - if (var->sync & FB_SYNC_HOR_HIGH_ACT) - par->beamcon0 |= BMC0_HSYTRUE; - if (var->sync & FB_SYNC_VERT_HIGH_ACT) - par->beamcon0 |= BMC0_VSYTRUE; - if (var->sync & FB_SYNC_COMP_HIGH_ACT) - par->beamcon0 |= BMC0_CSYTRUE; - htotal = par->htotal>>clk_shift; - vtotal = par->vtotal>>1; - } else { - DPRINTK("only broadcast modes possible for ocs\n"); - return -EINVAL; - } - - /* - * Checking the DMA timing - */ - - fconst = 16<<maxfmode<<clk_shift; - - /* - * smallest window start value without turn off other dma cycles - * than sprite1-7, unless you change min_fstrt - */ - - - fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64); - fstrt = downx(fconst, par->diwstrt_h-4) - fsize; - if (fstrt < min_fstrt) { - DPRINTK("fetch start too low\n"); - return -EINVAL; - } - - /* - * smallest window start value where smooth scrolling is possible - */ - - fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize; - if (fstrt < min_fstrt) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - maxfetchstop = down16(par->htotal - 80); - - fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst; - fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4))); - if (fstrt + fsize > maxfetchstop) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - fsize = upx(fconst, xres_n); - if (fstrt + fsize > maxfetchstop) { - DPRINTK("fetch stop too high\n"); - return -EINVAL; - } - - if (maxfmode + clk_shift <= 1) { - fsize = up64(xres_n + fconst - 1); - if (min_fstrt + fsize - 64 > maxfetchstop) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - fsize = up64(xres_n); - if (min_fstrt + fsize - 64 > maxfetchstop) { - DPRINTK("fetch size too high\n"); - return -EINVAL; - } - - fsize -= 64; - } else - fsize -= fconst; - - /* - * Check if there is enough time to update the bitplane pointers for ywrap - */ - - if (par->htotal-fsize-64 < par->bpp*64) - par->vmode &= ~FB_VMODE_YWRAP; - - /* - * Bitplane calculations and check the Memory Requirements - */ - - if (amifb_ilbm) { - par->next_plane = div8(upx(16<<maxfmode, par->vxres)); - par->next_line = par->bpp*par->next_plane; - if (par->next_line * par->vyres > fb_info.fix.smem_len) { - DPRINTK("too few video mem\n"); - return -EINVAL; - } - } else { - par->next_line = div8(upx(16<<maxfmode, par->vxres)); - par->next_plane = par->vyres*par->next_line; - if (par->next_plane * par->bpp > fb_info.fix.smem_len) { - DPRINTK("too few video mem\n"); - return -EINVAL; - } - } - - /* - * Hardware Register Values - */ - - par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; - if (!IS_OCS) - par->bplcon0 |= BPC0_ECSENA; - if (par->bpp == 8) - par->bplcon0 |= BPC0_BPU3; - else - par->bplcon0 |= par->bpp<<12; - if (var->nonstd == FB_NONSTD_HAM) - par->bplcon0 |= BPC0_HAM; - if (var->sync & FB_SYNC_EXT) - par->bplcon0 |= BPC0_ERSY; - - if (IS_AGA) - par->fmode = bplfetchmode[maxfmode]; - - switch (par->vmode & FB_VMODE_MASK) { - case FB_VMODE_INTERLACED: - par->bplcon0 |= BPC0_LACE; - break; - case FB_VMODE_DOUBLE: - if (IS_AGA) - par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; - break; - } - - if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { - par->xoffset = var->xoffset; - par->yoffset = var->yoffset; - if (par->vmode & FB_VMODE_YWRAP) { - if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres) - par->xoffset = par->yoffset = 0; - } else { - if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) || - par->yoffset < 0 || par->yoffset > par->vyres-par->yres) - par->xoffset = par->yoffset = 0; - } - } else - par->xoffset = par->yoffset = 0; - - par->crsr.crsr_x = par->crsr.crsr_y = 0; - par->crsr.spot_x = par->crsr.spot_y = 0; - par->crsr.height = par->crsr.width = 0; - - return 0; -} - - /* - * Fill the `var' structure based on the values in `par' and maybe - * other values read out of the hardware. - */ - -static int ami_encode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) -{ - u_short clk_shift, line_shift; - - memset(var, 0, sizeof(struct fb_var_screeninfo)); - - clk_shift = par->clk_shift; - line_shift = par->line_shift; - - var->xres = par->xres; - var->yres = par->yres; - var->xres_virtual = par->vxres; - var->yres_virtual = par->vyres; - var->xoffset = par->xoffset; - var->yoffset = par->yoffset; - - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - - var->red.offset = 0; - var->red.msb_right = 0; - var->red.length = par->bpp; - if (par->bplcon0 & BPC0_HAM) - var->red.length -= 2; - var->blue = var->green = var->red; - var->transp.offset = 0; - var->transp.length = 0; - var->transp.msb_right = 0; - - if (par->bplcon0 & BPC0_HAM) - var->nonstd = FB_NONSTD_HAM; - else - var->nonstd = 0; - var->activate = 0; - - var->height = -1; - var->width = -1; - - var->pixclock = pixclock[clk_shift]; - - if (IS_AGA && par->fmode & FMODE_BSCAN2) - var->vmode = FB_VMODE_DOUBLE; - else if (par->bplcon0 & BPC0_LACE) - var->vmode = FB_VMODE_INTERLACED; - else - var->vmode = FB_VMODE_NONINTERLACED; - - if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { - var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift; - var->right_margin = par->hsstrt>>clk_shift; - var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; - var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift; - var->lower_margin = par->vsstrt>>line_shift; - var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; - var->sync = 0; - if (par->beamcon0 & BMC0_HSYTRUE) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (par->beamcon0 & BMC0_VSYTRUE) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - if (par->beamcon0 & BMC0_CSYTRUE) - var->sync |= FB_SYNC_COMP_HIGH_ACT; - } else { - var->sync = FB_SYNC_BROADCAST; - var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); - var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; - var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; - var->vsync_len = 4>>line_shift; - var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; - var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - - var->lower_margin - var->vsync_len; - } - - if (par->bplcon0 & BPC0_ERSY) - var->sync |= FB_SYNC_EXT; - if (par->vmode & FB_VMODE_YWRAP) - var->vmode |= FB_VMODE_YWRAP; - - return 0; -} - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - * in `var'. - */ - -static void ami_pan_var(struct fb_var_screeninfo *var) -{ - struct amifb_par *par = ¤tpar; - - par->xoffset = var->xoffset; - par->yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - par->vmode |= FB_VMODE_YWRAP; - else - par->vmode &= ~FB_VMODE_YWRAP; - - do_vmode_pan = 0; - ami_update_par(); - do_vmode_pan = 1; -} - - /* - * Update hardware - */ - -static int ami_update_par(void) -{ - struct amifb_par *par = ¤tpar; - short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; - - clk_shift = par->clk_shift; - - if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) - par->xoffset = upx(16<<maxfmode, par->xoffset); - - fconst = 16<<maxfmode<<clk_shift; - vshift = modx(16<<maxfmode, par->xoffset); - fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4; - fsize = (par->xres+vshift)<<clk_shift; - shift = modx(fconst, fstrt); - move = downx(2<<maxfmode, div8(par->xoffset)); - if (maxfmode + clk_shift > 1) { - fstrt = downx(fconst, fstrt) - 64; - fsize = upx(fconst, fsize); - fstop = fstrt + fsize - fconst; - } else { - mod = fstrt = downx(fconst, fstrt) - fconst; - fstop = fstrt + upx(fconst, fsize) - 64; - fsize = up64(fsize); - fstrt = fstop - fsize + 64; - if (fstrt < min_fstrt) { - fstop += min_fstrt - fstrt; - fstrt = min_fstrt; - } - move = move - div8((mod-fstrt)>>clk_shift); - } - mod = par->next_line - div8(fsize>>clk_shift); - par->ddfstrt = fstrt; - par->ddfstop = fstop; - par->bplcon1 = hscroll2hw(shift); - par->bpl2mod = mod; - if (par->bplcon0 & BPC0_LACE) - par->bpl2mod += par->next_line; - if (IS_AGA && (par->fmode & FMODE_BSCAN2)) - par->bpl1mod = -div8(fsize>>clk_shift); - else - par->bpl1mod = par->bpl2mod; - - if (par->yoffset) { - par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move; - if (par->vmode & FB_VMODE_YWRAP) { - if (par->yoffset > par->vyres-par->yres) { - par->bplpt0wrap = fb_info.fix.smem_start + move; - if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset)) - par->bplpt0wrap += par->next_line; - } - } - } else - par->bplpt0 = fb_info.fix.smem_start + move; - - if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) - par->bplpt0 += par->next_line; - - return 0; -} - - - /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (IS_AGA) { - if (regno > 255) - return 1; - } else if (currentpar.bplcon0 & BPC0_SHRES) { - if (regno > 3) - return 1; - } else { - if (regno > 31) - return 1; - } - red >>= 8; - green >>= 8; - blue >>= 8; - if (!regno) { - red0 = red; - green0 = green; - blue0 = blue; - } - - /* - * Update the corresponding Hardware Color Register, unless it's Color - * Register 0 and the screen is blanked. - * - * VBlank is switched off to protect bplcon3 or ecs_palette[] from - * being changed by ami_do_blank() during the VBlank. - */ - - if (regno || !is_blanked) { -#if defined(CONFIG_FB_AMIGA_AGA) - if (IS_AGA) { - u_short bplcon3 = currentpar.bplcon3; - VBlankOff(); - custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); - custom.color[regno&31] = rgb2hw8_high(red, green, blue); - custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT; - custom.color[regno&31] = rgb2hw8_low(red, green, blue); - custom.bplcon3 = bplcon3; - VBlankOn(); - } else -#endif -#if defined(CONFIG_FB_AMIGA_ECS) - if (currentpar.bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - VBlankOff(); - for (i = regno+12; i >= (int)regno; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<=2; color >>= 2; - regno = down16(regno)+mul4(mod4(regno)); - for (i = regno+3; i >= (int)regno; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - VBlankOn(); - } else -#endif - custom.color[regno] = rgb2hw4(red, green, blue); - } - return 0; -} - -static void ami_update_display(void) -{ - struct amifb_par *par = ¤tpar; - - custom.bplcon1 = par->bplcon1; - custom.bpl1mod = par->bpl1mod; - custom.bpl2mod = par->bpl2mod; - custom.ddfstrt = ddfstrt2hw(par->ddfstrt); - custom.ddfstop = ddfstop2hw(par->ddfstop); -} - - /* - * Change the video mode (called by VBlank interrupt) - */ - -static void ami_init_display(void) -{ - struct amifb_par *par = ¤tpar; - int i; - - custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; - custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; - if (!IS_OCS) { - custom.bplcon3 = par->bplcon3; - if (IS_AGA) - custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; - if (par->beamcon0 & BMC0_VARBEAMEN) { - custom.htotal = htotal2hw(par->htotal); - custom.hbstrt = hbstrt2hw(par->hbstrt); - custom.hbstop = hbstop2hw(par->hbstop); - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.hcenter = hcenter2hw(par->hcenter); - custom.vtotal = vtotal2hw(par->vtotal); - custom.vbstrt = vbstrt2hw(par->vbstrt); - custom.vbstop = vbstop2hw(par->vbstop); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstop2hw(par->vsstop); - } - } - if (!IS_OCS || par->hsstop) - custom.beamcon0 = par->beamcon0; - if (IS_AGA) - custom.fmode = par->fmode; - - /* - * The minimum period for audio depends on htotal - */ - - amiga_audio_min_period = div16(par->htotal); - - is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; -#if 1 - if (is_lace) { - i = custom.vposr >> 15; - } else { - custom.vposw = custom.vposr | 0x8000; - i = 1; - } -#else - i = 1; - custom.vposw = custom.vposr | 0x8000; -#endif - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); -} - - /* - * (Un)Blank the screen (called by VBlank interrupt) + * Enable Display DMA */ + custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | + DMAF_BLITTER | DMAF_SPRITE; -static void ami_do_blank(void) -{ - struct amifb_par *par = ¤tpar; -#if defined(CONFIG_FB_AMIGA_AGA) - u_short bplcon3 = par->bplcon3; -#endif - u_char red, green, blue; - - if (do_blank > 0) { - custom.dmacon = DMAF_RASTER | DMAF_SPRITE; - red = green = blue = 0; - if (!IS_OCS && do_blank > 1) { - switch (do_blank) { - case FB_BLANK_VSYNC_SUSPEND: - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.vsstrt = vsstrt2hw(par->vtotal+4); - custom.vsstop = vsstop2hw(par->vtotal+4); - break; - case FB_BLANK_HSYNC_SUSPEND: - custom.hsstrt = hsstrt2hw(par->htotal+16); - custom.hsstop = hsstop2hw(par->htotal+16); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstrt2hw(par->vsstop); - break; - case FB_BLANK_POWERDOWN: - custom.hsstrt = hsstrt2hw(par->htotal+16); - custom.hsstop = hsstop2hw(par->htotal+16); - custom.vsstrt = vsstrt2hw(par->vtotal+4); - custom.vsstop = vsstop2hw(par->vtotal+4); - break; - } - if (!(par->beamcon0 & BMC0_VARBEAMEN)) { - custom.htotal = htotal2hw(par->htotal); - custom.vtotal = vtotal2hw(par->vtotal); - custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | - BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; - } - } - } else { - custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; - red = red0; - green = green0; - blue = blue0; - if (!IS_OCS) { - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstop2hw(par->vsstop); - custom.beamcon0 = par->beamcon0; - } - } -#if defined(CONFIG_FB_AMIGA_AGA) - if (IS_AGA) { - custom.bplcon3 = bplcon3; - custom.color[0] = rgb2hw8_high(red, green, blue); - custom.bplcon3 = bplcon3 | BPC3_LOCT; - custom.color[0] = rgb2hw8_low(red, green, blue); - custom.bplcon3 = bplcon3; - } else -#endif -#if defined(CONFIG_FB_AMIGA_ECS) - if (par->bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - for (i = 12; i >= 0; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<=2; color >>= 2; - for (i = 3; i >= 0; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - } else -#endif - custom.color[0] = rgb2hw4(red, green, blue); - is_blanked = do_blank > 0 ? do_blank : 0; -} - -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) -{ - struct amifb_par *par = ¤tpar; - - fix->crsr_width = fix->crsr_xsize = par->crsr.width; - fix->crsr_height = fix->crsr_ysize = par->crsr.height; - fix->crsr_color1 = 17; - fix->crsr_color2 = 18; - return 0; -} - -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) -{ - struct amifb_par *par = ¤tpar; - register u_short *lspr, *sspr; -#ifdef __mc68000__ - register u_long datawords asm ("d2"); -#else - register u_long datawords; -#endif - register short delta; - register u_char color; - short height, width, bits, words; - int size, alloc; - - size = par->crsr.height*par->crsr.width; - alloc = var->height*var->width; - var->height = par->crsr.height; - var->width = par->crsr.width; - var->xspot = par->crsr.spot_x; - var->yspot = par->crsr.spot_y; - if (size > var->height*var->width) - return -ENAMETOOLONG; - if (!access_ok(VERIFY_WRITE, data, size)) - return -EFAULT; - delta = 1<<par->crsr.fmode; - lspr = lofsprite + (delta<<1); - if (par->bplcon0 & BPC0_LACE) - sspr = shfsprite + (delta<<1); - else - sspr = NULL; - for (height = (short)var->height-1; height >= 0; height--) { - bits = 0; words = delta; datawords = 0; - for (width = (short)var->width-1; width >= 0; width--) { - if (bits == 0) { - bits = 16; --words; -#ifdef __mc68000__ - asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" - : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); -#else - datawords = (*(lspr+delta) << 16) | (*lspr++); -#endif - } - --bits; -#ifdef __mc68000__ - asm volatile ( - "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " - "swap %1 ; lslw #1,%1 ; roxlb #1,%0" - : "=d" (color), "=d" (datawords) : "1" (datawords)); -#else - color = (((datawords >> 30) & 2) - | ((datawords >> 15) & 1)); - datawords <<= 1; -#endif - put_user(color, data++); - } - if (bits > 0) { - --words; ++lspr; - } - while (--words >= 0) - ++lspr; -#ifdef __mc68000__ - asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" - : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); -#else - lspr += delta; - if (sspr) { - u_short *tmp = lspr; - lspr = sspr; - sspr = tmp; - } -#endif - } - return 0; -} - -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) -{ - struct amifb_par *par = ¤tpar; - register u_short *lspr, *sspr; -#ifdef __mc68000__ - register u_long datawords asm ("d2"); -#else - register u_long datawords; -#endif - register short delta; - u_short fmode; - short height, width, bits, words; + err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, + "fb vertb handler", info->par); + if (err) + goto disable_dma; - if (!var->width) - return -EINVAL; - else if (var->width <= 16) - fmode = TAG_FMODE_1; - else if (var->width <= 32) - fmode = TAG_FMODE_2; - else if (var->width <= 64) - fmode = TAG_FMODE_4; - else - return -EINVAL; - if (fmode > maxfmode) - return -EINVAL; - if (!var->height) - return -EINVAL; - if (!access_ok(VERIFY_READ, data, var->width*var->height)) - return -EFAULT; - delta = 1<<fmode; - lofsprite = shfsprite = (u_short *)spritememory; - lspr = lofsprite + (delta<<1); - if (par->bplcon0 & BPC0_LACE) { - if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE) - return -EINVAL; - memset(lspr, 0, (var->height+4)<<fmode<<2); - shfsprite += ((var->height+5)&-2)<<fmode; - sspr = shfsprite + (delta<<1); - } else { - if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE) - return -EINVAL; - memset(lspr, 0, (var->height+2)<<fmode<<2); - sspr = NULL; - } - for (height = (short)var->height-1; height >= 0; height--) { - bits = 16; words = delta; datawords = 0; - for (width = (short)var->width-1; width >= 0; width--) { - unsigned long tdata = 0; - get_user(tdata, data); - data++; -#ifdef __mc68000__ - asm volatile ( - "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " - "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" - : "=d" (datawords) - : "0" (datawords), "d" (tdata)); -#else - datawords = ((datawords << 1) & 0xfffefffe); - datawords |= tdata & 1; - datawords |= (tdata & 2) << (16-1); -#endif - if (--bits == 0) { - bits = 16; --words; -#ifdef __mc68000__ - asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); -#else - *(lspr+delta) = (u_short) (datawords >> 16); - *lspr++ = (u_short) (datawords & 0xffff); -#endif - } - } - if (bits < 16) { - --words; -#ifdef __mc68000__ - asm volatile ( - "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " - "swap %2 ; lslw %4,%2 ; movew %2,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); -#else - *(lspr+delta) = (u_short) (datawords >> (16+bits)); - *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); -#endif - } - while (--words >= 0) { -#ifdef __mc68000__ - asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); -#else - *(lspr+delta) = 0; - *lspr++ = 0; -#endif - } -#ifdef __mc68000__ - asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" - : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); -#else - lspr += delta; - if (sspr) { - u_short *tmp = lspr; - lspr = sspr; - sspr = tmp; - } -#endif - } - par->crsr.height = var->height; - par->crsr.width = var->width; - par->crsr.spot_x = var->xspot; - par->crsr.spot_y = var->yspot; - par->crsr.fmode = fmode; - if (IS_AGA) { - par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); - par->fmode |= sprfetchmode[fmode]; - custom.fmode = par->fmode; - } - return 0; -} + err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); + if (err) + goto free_irq; -static int ami_get_cursorstate(struct fb_cursorstate *state) -{ - struct amifb_par *par = ¤tpar; + dev_set_drvdata(&pdev->dev, info); - state->xoffset = par->crsr.crsr_x; - state->yoffset = par->crsr.crsr_y; - state->mode = cursormode; - return 0; -} + err = register_framebuffer(info); + if (err) + goto unset_drvdata; -static int ami_set_cursorstate(struct fb_cursorstate *state) -{ - struct amifb_par *par = ¤tpar; + printk("fb%d: %s frame buffer device, using %dK of video memory\n", + info->node, info->fix.id, info->fix.smem_len>>10); - par->crsr.crsr_x = state->xoffset; - par->crsr.crsr_y = state->yoffset; - if ((cursormode = state->mode) == FB_CURSOR_OFF) - cursorstate = -1; - do_cursor = 1; return 0; -} - -static void ami_set_sprite(void) -{ - struct amifb_par *par = ¤tpar; - copins *copl, *cops; - u_short hs, vs, ve; - u_long pl, ps, pt; - short mx, my; - - cops = copdisplay.list[currentcop][0]; - copl = copdisplay.list[currentcop][1]; - ps = pl = ZTWO_PADDR(dummysprite); - mx = par->crsr.crsr_x-par->crsr.spot_x; - my = par->crsr.crsr_y-par->crsr.spot_y; - if (!(par->vmode & FB_VMODE_YWRAP)) { - mx -= par->xoffset; - my -= par->yoffset; - } - if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && - mx > -(short)par->crsr.width && mx < par->xres && - my > -(short)par->crsr.height && my < par->yres) { - pl = ZTWO_PADDR(lofsprite); - hs = par->diwstrt_h + (mx<<par->clk_shift) - 4; - vs = par->diwstrt_v + (my<<par->line_shift); - ve = vs + (par->crsr.height<<par->line_shift); - if (par->bplcon0 & BPC0_LACE) { - ps = ZTWO_PADDR(shfsprite); - lofsprite[0] = spr2hw_pos(vs, hs); - shfsprite[0] = spr2hw_pos(vs+1, hs); - if (mod2(vs)) { - lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); - shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1); - pt = pl; pl = ps; ps = pt; - } else { - lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1); - shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve); - } - } else { - lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); - lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); - } - } - copl[cop_spr0ptrh].w[1] = highw(pl); - copl[cop_spr0ptrl].w[1] = loww(pl); - if (par->bplcon0 & BPC0_LACE) { - cops[cop_spr0ptrh].w[1] = highw(ps); - cops[cop_spr0ptrl].w[1] = loww(ps); - } -} - - - /* - * Initialise the Copper Initialisation List - */ - -static void __init ami_init_copper(void) -{ - copins *cop = copdisplay.init; - u_long p; - int i; - - if (!IS_OCS) { - (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); - (cop++)->l = CMOVE(0x0181, diwstrt); - (cop++)->l = CMOVE(0x0281, diwstop); - (cop++)->l = CMOVE(0x0000, diwhigh); - } else - (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); - p = ZTWO_PADDR(dummysprite); - for (i = 0; i < 8; i++) { - (cop++)->l = CMOVE(0, spr[i].pos); - (cop++)->l = CMOVE(highw(p), sprpt[i]); - (cop++)->l = CMOVE2(loww(p), sprpt[i]); - } - - (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); - copdisplay.wait = cop; - (cop++)->l = CEND; - (cop++)->l = CMOVE(0, copjmp2); - cop->l = CEND; - - custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); - custom.copjmp1 = 0; -} -static void ami_reinit_copper(void) -{ - struct amifb_par *par = ¤tpar; - - copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; - copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4); +unset_drvdata: + dev_set_drvdata(&pdev->dev, NULL); + fb_dealloc_cmap(&info->cmap); +free_irq: + free_irq(IRQ_AMIGA_COPPER, info->par); +disable_dma: + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); +release: + framebuffer_release(info); + return err; } - /* - * Build the Copper List - */ - -static void ami_build_copper(void) -{ - struct amifb_par *par = ¤tpar; - copins *copl, *cops; - u_long p; - - currentcop = 1 - currentcop; - - copl = copdisplay.list[currentcop][1]; - - (copl++)->l = CWAIT(0, 10); - (copl++)->l = CMOVE(par->bplcon0, bplcon0); - (copl++)->l = CMOVE(0, sprpt[0]); - (copl++)->l = CMOVE2(0, sprpt[0]); - - if (par->bplcon0 & BPC0_LACE) { - cops = copdisplay.list[currentcop][0]; - - (cops++)->l = CWAIT(0, 10); - (cops++)->l = CMOVE(par->bplcon0, bplcon0); - (cops++)->l = CMOVE(0, sprpt[0]); - (cops++)->l = CMOVE2(0, sprpt[0]); - - (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt); - (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop); - (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); - (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); - if (!IS_OCS) { - (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1, - par->diwstop_h, par->diwstop_v+1), diwhigh); - (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, - par->diwstop_h, par->diwstop_v), diwhigh); -#if 0 - if (par->beamcon0 & BMC0_VARBEAMEN) { - (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt); - (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop); - (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); - (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); - } -#endif - } - p = ZTWO_PADDR(copdisplay.list[currentcop][0]); - (copl++)->l = CMOVE(highw(p), cop2lc); - (copl++)->l = CMOVE2(loww(p), cop2lc); - p = ZTWO_PADDR(copdisplay.list[currentcop][1]); - (cops++)->l = CMOVE(highw(p), cop2lc); - (cops++)->l = CMOVE2(loww(p), cop2lc); - copdisplay.rebuild[0] = cops; - } else { - (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); - (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); - if (!IS_OCS) { - (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, - par->diwstop_h, par->diwstop_v), diwhigh); -#if 0 - if (par->beamcon0 & BMC0_VARBEAMEN) { - (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); - (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); - } -#endif - } - } - copdisplay.rebuild[1] = copl; - - ami_update_par(); - ami_rebuild_copper(); -} - - /* - * Rebuild the Copper List - * - * We only change the things that are not static - */ - -static void ami_rebuild_copper(void) -{ - struct amifb_par *par = ¤tpar; - copins *copl, *cops; - u_short line, h_end1, h_end2; - short i; - u_long p; - - if (IS_AGA && maxfmode + par->clk_shift == 0) - h_end1 = par->diwstrt_h-64; - else - h_end1 = par->htotal-32; - h_end2 = par->ddfstop+64; - - ami_set_sprite(); - - copl = copdisplay.rebuild[1]; - p = par->bplpt0; - if (par->vmode & FB_VMODE_YWRAP) { - if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) { - if (par->yoffset > par->vyres-par->yres) { - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (copl++)->l = CMOVE(highw(p), bplpt[i]); - (copl++)->l = CMOVE2(loww(p), bplpt[i]); - } - line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1; - while (line >= 512) { - (copl++)->l = CWAIT(h_end1, 510); - line -= 512; - } - if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) - (copl++)->l = CWAIT(h_end1, line); - else - (copl++)->l = CWAIT(h_end2, line); - p = par->bplpt0wrap; - } - } else p = par->bplpt0wrap; - } - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (copl++)->l = CMOVE(highw(p), bplpt[i]); - (copl++)->l = CMOVE2(loww(p), bplpt[i]); - } - copl->l = CEND; - - if (par->bplcon0 & BPC0_LACE) { - cops = copdisplay.rebuild[0]; - p = par->bplpt0; - if (mod2(par->diwstrt_v)) - p -= par->next_line; - else - p += par->next_line; - if (par->vmode & FB_VMODE_YWRAP) { - if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) { - if (par->yoffset > par->vyres-par->yres+1) { - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (cops++)->l = CMOVE(highw(p), bplpt[i]); - (cops++)->l = CMOVE2(loww(p), bplpt[i]); - } - line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2; - while (line >= 512) { - (cops++)->l = CWAIT(h_end1, 510); - line -= 512; - } - if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) - (cops++)->l = CWAIT(h_end1, line); - else - (cops++)->l = CWAIT(h_end2, line); - p = par->bplpt0wrap; - if (mod2(par->diwstrt_v+par->vyres-par->yoffset)) - p -= par->next_line; - else - p += par->next_line; - } - } else p = par->bplpt0wrap - par->next_line; - } - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (cops++)->l = CMOVE(highw(p), bplpt[i]); - (cops++)->l = CMOVE2(loww(p), bplpt[i]); - } - cops->l = CEND; - } -} static int __exit amifb_remove(struct platform_device *pdev) { - unregister_framebuffer(&fb_info); - amifb_deinit(pdev); + struct fb_info *info = dev_get_drvdata(&pdev->dev); + + unregister_framebuffer(info); + dev_set_drvdata(&pdev->dev, NULL); + fb_dealloc_cmap(&info->cmap); + free_irq(IRQ_AMIGA_COPPER, info->par); + custom.dmacon = DMAF_ALL | DMAF_MASTER; + if (videomemory) + iounmap((void *)videomemory); + chipfree(); + framebuffer_release(info); amifb_video_off(); return 0; } diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 63409c122ae8..0d7b20d4285d 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -100,8 +100,11 @@ static int atmel_bl_update_status(struct backlight_device *bl) brightness = 0; lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); - lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, + if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE) + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, brightness ? contrast_ctr : 0); + else + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; @@ -682,14 +685,30 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, case FB_VISUAL_PSEUDOCOLOR: if (regno < 256) { - val = ((red >> 11) & 0x001f); - val |= ((green >> 6) & 0x03e0); - val |= ((blue >> 1) & 0x7c00); - - /* - * TODO: intensity bit. Maybe something like - * ~(red[10] ^ green[10] ^ blue[10]) & 1 - */ + if (cpu_is_at91sam9261() || cpu_is_at91sam9263() + || cpu_is_at91sam9rl()) { + /* old style I+BGR:555 */ + val = ((red >> 11) & 0x001f); + val |= ((green >> 6) & 0x03e0); + val |= ((blue >> 1) & 0x7c00); + + /* + * TODO: intensity bit. Maybe something like + * ~(red[10] ^ green[10] ^ blue[10]) & 1 + */ + } else { + /* new style BGR:565 / RGB:565 */ + if (sinfo->lcd_wiring_mode == + ATMEL_LCDC_WIRING_RGB) { + val = ((blue >> 11) & 0x001f); + val |= ((red >> 0) & 0xf800); + } else { + val = ((red >> 11) & 0x001f); + val |= ((blue >> 0) & 0xf800); + } + + val |= ((green >> 5) & 0x07e0); + } lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ret = 0; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 44bdce4242ad..622f12b62a47 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -301,9 +301,9 @@ static struct fb_ops atyfb_ops = { .fb_sync = atyfb_sync, }; -static int noaccel; +static bool noaccel; #ifdef CONFIG_MTRR -static int nomtrr; +static bool nomtrr; #endif static int vram; static int pll; diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 150684882ef7..ce1506b75adf 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -263,19 +263,19 @@ static reg_val common_regs[] = { static char *mode_option; static char *monitor_layout; -static int noaccel = 0; +static bool noaccel = 0; static int default_dynclk = -2; -static int nomodeset = 0; -static int ignore_edid = 0; -static int mirror = 0; +static bool nomodeset = 0; +static bool ignore_edid = 0; +static bool mirror = 0; static int panel_yres = 0; -static int force_dfp = 0; -static int force_measure_pll = 0; +static bool force_dfp = 0; +static bool force_measure_pll = 0; #ifdef CONFIG_MTRR -static int nomtrr = 0; +static bool nomtrr = 0; #endif -static int force_sleep; -static int ignore_devlist; +static bool force_sleep; +static bool ignore_devlist; #ifdef CONFIG_PMAC_BACKLIGHT static int backlight = 1; #else diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index 649cb35de4ed..de9da6774fd9 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -60,18 +60,6 @@ #include "au1100fb.h" -/* - * Sanity check. If this is a new Au1100 based board, search for - * the PB1100 ifdefs to make sure you modify the code accordingly. - */ -#if defined(CONFIG_MIPS_PB1100) - #include <asm/mach-pb1x00/pb1100.h> -#elif defined(CONFIG_MIPS_DB1100) - #include <asm/mach-db1x00/db1x00.h> -#else - #error "Unknown Au1100 board, Au1100 FB driver not supported" -#endif - #define DRIVER_NAME "au1100fb" #define DRIVER_DESC "LCD controller driver for AU1100 processors" diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 72005598040f..04e4479d5afd 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -44,6 +44,7 @@ #include <linux/slab.h> #include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1200fb.h> /* platform_data */ #include "au1200fb.h" #define DRIVER_NAME "au1200fb" @@ -143,6 +144,7 @@ struct au1200_lcd_iodata_t { /* Private, per-framebuffer management information (independent of the panel itself) */ struct au1200fb_device { struct fb_info *fb_info; /* FB driver info record */ + struct au1200fb_platdata *pd; int plane; unsigned char* fb_mem; /* FrameBuffer memory map */ @@ -201,9 +203,6 @@ struct window_settings { #define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01 #endif -extern int board_au1200fb_panel_init (void); -extern int board_au1200fb_panel_shutdown (void); - /* * Default window configurations */ @@ -334,8 +333,6 @@ struct panel_settings uint32 mode_toyclksrc; uint32 mode_backlight; uint32 mode_auxpll; - int (*device_init)(void); - int (*device_shutdown)(void); #define Xres min_xres #define Yres min_yres u32 min_xres; /* Minimum horizontal resolution */ @@ -385,8 +382,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 320, 320, 240, 240, }, @@ -415,8 +410,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 640, 480, 640, 480, }, @@ -445,8 +438,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 800, 800, 600, 600, }, @@ -475,8 +466,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 6, /* 72MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 1024, 1024, 768, 768, }, @@ -505,8 +494,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 10, /* 120MHz AUXPLL */ - .device_init = NULL, - .device_shutdown = NULL, 1280, 1280, 1024, 1024, }, @@ -535,8 +522,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 1024, 1024, 768, 768, }, @@ -568,8 +553,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 640, 480, 640, 480, }, @@ -601,8 +584,6 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 320, 320, 240, 240, }, @@ -634,11 +615,43 @@ static struct panel_settings known_lcd_panels[] = .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ .mode_backlight = 0x00000000, .mode_auxpll = 8, /* 96MHz AUXPLL */ - .device_init = board_au1200fb_panel_init, - .device_shutdown = board_au1200fb_panel_shutdown, 856, 856, 480, 480, }, + [9] = { + .name = "DB1300_800x480", + .monspecs = { + .modedb = NULL, + .modedb_len = 0, + .hfmin = 30000, + .hfmax = 70000, + .vfmin = 60, + .vfmax = 60, + .dclkmin = 6000000, + .dclkmax = 28000000, + .input = FB_DISP_RGB, + }, + .mode_screen = LCD_SCREEN_SX_N(800) | + LCD_SCREEN_SY_N(480), + .mode_horztiming = LCD_HORZTIMING_HPW_N(5) | + LCD_HORZTIMING_HND1_N(16) | + LCD_HORZTIMING_HND2_N(8), + .mode_verttiming = LCD_VERTTIMING_VPW_N(4) | + LCD_VERTTIMING_VND1_N(8) | + LCD_VERTTIMING_VND2_N(5), + .mode_clkcontrol = LCD_CLKCONTROL_PCD_N(1) | + LCD_CLKCONTROL_IV | + LCD_CLKCONTROL_IH, + .mode_pwmdiv = 0x00000000, + .mode_pwmhi = 0x00000000, + .mode_outmask = 0x00FFFFFF, + .mode_fifoctrl = 0x2f2f2f2f, + .mode_toyclksrc = 0x00000004, /* AUXPLL directly */ + .mode_backlight = 0x00000000, + .mode_auxpll = (48/12) * 2, + 800, 800, + 480, 480, + }, }; #define NUM_PANELS (ARRAY_SIZE(known_lcd_panels)) @@ -764,7 +777,8 @@ static int au1200_setlocation (struct au1200fb_device *fbdev, int plane, return 0; } -static void au1200_setpanel (struct panel_settings *newpanel) +static void au1200_setpanel(struct panel_settings *newpanel, + struct au1200fb_platdata *pd) { /* * Perform global setup/init of LCD controller @@ -798,8 +812,8 @@ static void au1200_setpanel (struct panel_settings *newpanel) the controller, the clock cannot be turned off before first shutting down the controller. */ - if (panel->device_shutdown != NULL) - panel->device_shutdown(); + if (pd->panel_shutdown) + pd->panel_shutdown(); } /* Newpanel == NULL indicates a shutdown operation only */ @@ -852,7 +866,8 @@ static void au1200_setpanel (struct panel_settings *newpanel) au_sync(); /* Call init of panel */ - if (panel->device_init != NULL) panel->device_init(); + if (pd->panel_init) + pd->panel_init(); /* FIX!!!! not appropriate on panel change!!! Global setup/init */ lcd->intenable = 0; @@ -1185,6 +1200,8 @@ static int au1200fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, */ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) { + struct au1200fb_device *fbdev = fbi->par; + /* Short-circuit screen blanking */ if (noblanking) return 0; @@ -1194,13 +1211,13 @@ static int au1200fb_fb_blank(int blank_mode, struct fb_info *fbi) case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: /* printk("turn on panel\n"); */ - au1200_setpanel(panel); + au1200_setpanel(panel, fbdev->pd); break; case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: /* printk("turn off panel\n"); */ - au1200_setpanel(NULL); + au1200_setpanel(NULL, fbdev->pd); break; default: break; @@ -1428,6 +1445,7 @@ static void get_window(unsigned int plane, static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { + struct au1200fb_device *fbdev = info->par; int plane; int val; @@ -1472,7 +1490,7 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, struct panel_settings *newpanel; panel_index = iodata.global.panel_choice; newpanel = &known_lcd_panels[panel_index]; - au1200_setpanel(newpanel); + au1200_setpanel(newpanel, fbdev->pd); } break; @@ -1588,22 +1606,102 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) /*-------------------------------------------------------------------------*/ -/* AU1200 LCD controller device driver */ +static int au1200fb_setup(struct au1200fb_platdata *pd) +{ + char *options = NULL; + char *this_opt, *endptr; + int num_panels = ARRAY_SIZE(known_lcd_panels); + int panel_idx = -1; + + fb_get_options(DRIVER_NAME, &options); + + if (!options) + goto out; + + while ((this_opt = strsep(&options, ",")) != NULL) { + /* Panel option - can be panel name, + * "bs" for board-switch, or number/index */ + if (!strncmp(this_opt, "panel:", 6)) { + int i; + long int li; + char *endptr; + this_opt += 6; + /* First check for index, which allows + * to short circuit this mess */ + li = simple_strtol(this_opt, &endptr, 0); + if (*endptr == '\0') + panel_idx = (int)li; + else if (strcmp(this_opt, "bs") == 0) + panel_idx = pd->panel_index(); + else { + for (i = 0; i < num_panels; i++) { + if (!strcmp(this_opt, + known_lcd_panels[i].name)) { + panel_idx = i; + break; + } + } + } + if ((panel_idx < 0) || (panel_idx >= num_panels)) + print_warn("Panel %s not supported!", this_opt); + else + panel_index = panel_idx; + + } else if (strncmp(this_opt, "nohwcursor", 10) == 0) + nohwcursor = 1; + else if (strncmp(this_opt, "devices:", 8) == 0) { + this_opt += 8; + device_count = simple_strtol(this_opt, &endptr, 0); + if ((device_count < 0) || + (device_count > MAX_DEVICE_COUNT)) + device_count = MAX_DEVICE_COUNT; + } else if (strncmp(this_opt, "wincfg:", 7) == 0) { + this_opt += 7; + window_index = simple_strtol(this_opt, &endptr, 0); + if ((window_index < 0) || + (window_index >= ARRAY_SIZE(windows))) + window_index = DEFAULT_WINDOW_INDEX; + } else if (strncmp(this_opt, "off", 3) == 0) + return 1; + else + print_warn("Unsupported option \"%s\"", this_opt); + } + +out: + return 0; +} + +/* AU1200 LCD controller device driver */ static int __devinit au1200fb_drv_probe(struct platform_device *dev) { struct au1200fb_device *fbdev; + struct au1200fb_platdata *pd; struct fb_info *fbi = NULL; unsigned long page; int bpp, plane, ret, irq; + print_info("" DRIVER_DESC ""); + + pd = dev->dev.platform_data; + if (!pd) + return -ENODEV; + + /* Setup driver with options */ + if (au1200fb_setup(pd)) + return -ENODEV; + + /* Point to the panel selected */ + panel = &known_lcd_panels[panel_index]; + win = &windows[window_index]; + + printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); + printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); + /* shut gcc up */ ret = 0; fbdev = NULL; - /* Kickstart the panel */ - au1200_setpanel(panel); - for (plane = 0; plane < device_count; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); if (win->w[plane].xres == 0) @@ -1619,6 +1717,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) _au1200fb_infos[plane] = fbi; fbdev = fbi->par; fbdev->fb_info = fbi; + fbdev->pd = pd; fbdev->plane = plane; @@ -1680,6 +1779,11 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) goto failed; } + platform_set_drvdata(dev, pd); + + /* Kickstart the panel */ + au1200_setpanel(panel, pd); + return 0; failed: @@ -1699,12 +1803,13 @@ failed: static int __devexit au1200fb_drv_remove(struct platform_device *dev) { + struct au1200fb_platdata *pd = platform_get_drvdata(dev); struct au1200fb_device *fbdev; struct fb_info *fbi; int plane; /* Turn off the panel */ - au1200_setpanel(NULL); + au1200_setpanel(NULL, pd); for (plane = 0; plane < device_count; ++plane) { fbi = _au1200fb_infos[plane]; @@ -1732,7 +1837,8 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev) #ifdef CONFIG_PM static int au1200fb_drv_suspend(struct device *dev) { - au1200_setpanel(NULL); + struct au1200fb_platdata *pd = dev_get_drvdata(dev); + au1200_setpanel(NULL, pd); lcd->outmask = 0; au_sync(); @@ -1742,11 +1848,12 @@ static int au1200fb_drv_suspend(struct device *dev) static int au1200fb_drv_resume(struct device *dev) { + struct au1200fb_platdata *pd = dev_get_drvdata(dev); struct fb_info *fbi; int i; /* Kickstart the panel */ - au1200_setpanel(panel); + au1200_setpanel(panel, pd); for (i = 0; i < device_count; i++) { fbi = _au1200fb_infos[i]; @@ -1781,100 +1888,8 @@ static struct platform_driver au1200fb_driver = { /*-------------------------------------------------------------------------*/ -/* Kernel driver */ - -static int au1200fb_setup(void) -{ - char *options = NULL; - char *this_opt, *endptr; - int num_panels = ARRAY_SIZE(known_lcd_panels); - int panel_idx = -1; - - fb_get_options(DRIVER_NAME, &options); - - if (options) { - while ((this_opt = strsep(&options,",")) != NULL) { - /* Panel option - can be panel name, - * "bs" for board-switch, or number/index */ - if (!strncmp(this_opt, "panel:", 6)) { - int i; - long int li; - char *endptr; - this_opt += 6; - /* First check for index, which allows - * to short circuit this mess */ - li = simple_strtol(this_opt, &endptr, 0); - if (*endptr == '\0') { - panel_idx = (int)li; - } - else if (strcmp(this_opt, "bs") == 0) { - extern int board_au1200fb_panel(void); - panel_idx = board_au1200fb_panel(); - } - - else - for (i = 0; i < num_panels; i++) { - if (!strcmp(this_opt, known_lcd_panels[i].name)) { - panel_idx = i; - break; - } - } - - if ((panel_idx < 0) || (panel_idx >= num_panels)) { - print_warn("Panel %s not supported!", this_opt); - } - else - panel_index = panel_idx; - } - - else if (strncmp(this_opt, "nohwcursor", 10) == 0) { - nohwcursor = 1; - } - - else if (strncmp(this_opt, "devices:", 8) == 0) { - this_opt += 8; - device_count = simple_strtol(this_opt, - &endptr, 0); - if ((device_count < 0) || - (device_count > MAX_DEVICE_COUNT)) - device_count = MAX_DEVICE_COUNT; - } - - else if (strncmp(this_opt, "wincfg:", 7) == 0) { - this_opt += 7; - window_index = simple_strtol(this_opt, - &endptr, 0); - if ((window_index < 0) || - (window_index >= ARRAY_SIZE(windows))) - window_index = DEFAULT_WINDOW_INDEX; - } - - else if (strncmp(this_opt, "off", 3) == 0) - return 1; - /* Unsupported option */ - else { - print_warn("Unsupported option \"%s\"", this_opt); - } - } - } - return 0; -} - static int __init au1200fb_init(void) { - print_info("" DRIVER_DESC ""); - - /* Setup driver with options */ - if (au1200fb_setup()) - return -ENODEV; - - /* Point to the panel selected */ - panel = &known_lcd_panels[panel_index]; - win = &windows[window_index]; - - printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); - printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); - return platform_driver_register(&au1200fb_driver); } diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 6df7c54db0a3..738c8ce7d132 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -280,52 +280,74 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); #endif /* CONFIG_PCI */ #ifdef CONFIG_ZORRO -static const struct zorro_device_id cirrusfb_zorro_table[] = { +struct zorrocl { + enum cirrus_board type; /* Board type */ + u32 regoffset; /* Offset of registers in first Zorro device */ + u32 ramsize; /* Size of video RAM in first Zorro device */ + /* If zero, use autoprobe on RAM device */ + u32 ramoffset; /* Offset of video RAM in first Zorro device */ + zorro_id ramid; /* Zorro ID of RAM device */ + zorro_id ramid2; /* Zorro ID of optional second RAM device */ +}; + +static const struct zorrocl zcl_sd64 __devinitconst = { + .type = BT_SD64, + .ramid = ZORRO_PROD_HELFRICH_SD64_RAM, +}; + +static const struct zorrocl zcl_piccolo __devinitconst = { + .type = BT_PICCOLO, + .ramid = ZORRO_PROD_HELFRICH_PICCOLO_RAM, +}; + +static const struct zorrocl zcl_picasso __devinitconst = { + .type = BT_PICASSO, + .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, +}; + +static const struct zorrocl zcl_spectrum __devinitconst = { + .type = BT_SPECTRUM, + .ramid = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, +}; + +static const struct zorrocl zcl_picasso4_z3 __devinitconst = { + .type = BT_PICASSO4, + .regoffset = 0x00600000, + .ramsize = 4 * MB_, + .ramoffset = 0x01000000, /* 0x02000000 for 64 MiB boards */ +}; + +static const struct zorrocl zcl_picasso4_z2 __devinitconst = { + .type = BT_PICASSO4, + .regoffset = 0x10000, + .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1, + .ramid2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2, +}; + + +static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = { { - .id = ZORRO_PROD_HELFRICH_SD64_RAM, - .driver_data = BT_SD64, + .id = ZORRO_PROD_HELFRICH_SD64_REG, + .driver_data = (unsigned long)&zcl_sd64, }, { - .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, - .driver_data = BT_PICCOLO, + .id = ZORRO_PROD_HELFRICH_PICCOLO_REG, + .driver_data = (unsigned long)&zcl_piccolo, }, { - .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, - .driver_data = BT_PICASSO, + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, + .driver_data = (unsigned long)&zcl_picasso, }, { - .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, - .driver_data = BT_SPECTRUM, + .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, + .driver_data = (unsigned long)&zcl_spectrum, }, { .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, - .driver_data = BT_PICASSO4, + .driver_data = (unsigned long)&zcl_picasso4_z3, + }, { + .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG, + .driver_data = (unsigned long)&zcl_picasso4_z2, }, { 0 } }; MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); - -static const struct { - zorro_id id2; - unsigned long size; -} cirrusfb_zorro_table2[] = { - [BT_SD64] = { - .id2 = ZORRO_PROD_HELFRICH_SD64_REG, - .size = 0x400000 - }, - [BT_PICCOLO] = { - .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG, - .size = 0x200000 - }, - [BT_PICASSO] = { - .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, - .size = 0x200000 - }, - [BT_SPECTRUM] = { - .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, - .size = 0x200000 - }, - [BT_PICASSO4] = { - .id2 = 0, - .size = 0x400000 - } -}; #endif /* CONFIG_ZORRO */ #ifdef CIRRUSFB_DEBUG @@ -350,7 +372,7 @@ struct cirrusfb_info { void (*unmap)(struct fb_info *info); }; -static int noaccel __devinitdata; +static bool noaccel __devinitdata; static char *mode_option __devinitdata = "640x480@60"; /****************************************************************************/ @@ -1956,16 +1978,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) struct cirrusfb_info *cinfo = info->par; struct zorro_dev *zdev = to_zorro_dev(info->device); - zorro_release_device(zdev); - - if (cinfo->btype == BT_PICASSO4) { - cinfo->regbase -= 0x600000; - iounmap((void *)cinfo->regbase); + if (info->fix.smem_start > 16 * MB_) iounmap(info->screen_base); - } else { - if (zorro_resource_start(zdev) > 0x01000000) - iounmap(info->screen_base); - } + if (info->fix.mmio_start > 16 * MB_) + iounmap(cinfo->regbase); + + zorro_release_device(zdev); } #endif /* CONFIG_ZORRO */ @@ -2222,115 +2240,116 @@ static struct pci_driver cirrusfb_pci_driver = { static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, const struct zorro_device_id *ent) { - struct cirrusfb_info *cinfo; struct fb_info *info; + int error; + const struct zorrocl *zcl; enum cirrus_board btype; - struct zorro_dev *z2 = NULL; - unsigned long board_addr, board_size, size; - int ret; - - btype = ent->driver_data; - if (cirrusfb_zorro_table2[btype].id2) - z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); - size = cirrusfb_zorro_table2[btype].size; + unsigned long regbase, ramsize, rambase; + struct cirrusfb_info *cinfo; info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); if (!info) { printk(KERN_ERR "cirrusfb: could not allocate memory\n"); - ret = -ENOMEM; - goto err_out; + return -ENOMEM; + } + + zcl = (const struct zorrocl *)ent->driver_data; + btype = zcl->type; + regbase = zorro_resource_start(z) + zcl->regoffset; + ramsize = zcl->ramsize; + if (ramsize) { + rambase = zorro_resource_start(z) + zcl->ramoffset; + if (zorro_resource_len(z) == 64 * MB_) { + /* Quirk for 64 MiB Picasso IV */ + rambase += zcl->ramoffset; + } + } else { + struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL); + if (!ram || !zorro_resource_len(ram)) { + dev_err(info->device, "No video RAM found\n"); + error = -ENODEV; + goto err_release_fb; + } + rambase = zorro_resource_start(ram); + ramsize = zorro_resource_len(ram); + if (zcl->ramid2 && + (ram = zorro_find_device(zcl->ramid2, NULL))) { + if (zorro_resource_start(ram) != rambase + ramsize) { + dev_warn(info->device, + "Skipping non-contiguous RAM at %pR\n", + &ram->resource); + } else { + ramsize += zorro_resource_len(ram); + } + } } - dev_info(info->device, "%s board detected\n", - cirrusfb_board_info[btype].name); - - cinfo = info->par; - cinfo->btype = btype; - - assert(z); - assert(btype != BT_NONE); - - board_addr = zorro_resource_start(z); - board_size = zorro_resource_len(z); - info->screen_size = size; + dev_info(info->device, + "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n", + cirrusfb_board_info[btype].name, regbase, ramsize / MB_, + rambase); if (!zorro_request_device(z, "cirrusfb")) { - dev_err(info->device, "cannot reserve region 0x%lx, abort\n", - board_addr); - ret = -EBUSY; + dev_err(info->device, "Cannot reserve %pR\n", &z->resource); + error = -EBUSY; goto err_release_fb; } - ret = -EIO; - - if (btype == BT_PICASSO4) { - dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000); - - /* To be precise, for the P4 this is not the */ - /* begin of the board, but the begin of RAM. */ - /* for P4, map in its address space in 2 chunks (### TEST! ) */ - /* (note the ugly hardcoded 16M number) */ - cinfo->regbase = ioremap(board_addr, 16777216); - if (!cinfo->regbase) - goto err_release_region; - - dev_dbg(info->device, "Virtual address for board set to: $%p\n", - cinfo->regbase); - cinfo->regbase += 0x600000; - info->fix.mmio_start = board_addr + 0x600000; - - info->fix.smem_start = board_addr + 16777216; - info->screen_base = ioremap(info->fix.smem_start, 16777216); - if (!info->screen_base) - goto err_unmap_regbase; - } else { - dev_info(info->device, " REG at $%lx\n", - (unsigned long) z2->resource.start); - - info->fix.smem_start = board_addr; - if (board_addr > 0x01000000) - info->screen_base = ioremap(board_addr, board_size); - else - info->screen_base = (caddr_t) ZTWO_VADDR(board_addr); - if (!info->screen_base) - goto err_release_region; + cinfo = info->par; + cinfo->btype = btype; - /* set address for REG area of board */ - cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); - info->fix.mmio_start = z2->resource.start; + info->fix.mmio_start = regbase; + cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024) + : (caddr_t)ZTWO_VADDR(regbase); + if (!cinfo->regbase) { + dev_err(info->device, "Cannot map registers\n"); + error = -EIO; + goto err_release_dev; + } - dev_dbg(info->device, "Virtual address for board set to: $%p\n", - cinfo->regbase); + info->fix.smem_start = rambase; + info->screen_size = ramsize; + info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize) + : (caddr_t)ZTWO_VADDR(rambase); + if (!info->screen_base) { + dev_err(info->device, "Cannot map video RAM\n"); + error = -EIO; + goto err_unmap_reg; } + cinfo->unmap = cirrusfb_zorro_unmap; dev_info(info->device, - "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", - board_size / MB_, board_addr); - - zorro_set_drvdata(z, info); + "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n", + ramsize / MB_, rambase); /* MCLK select etc. */ if (cirrusfb_board_info[btype].init_sr1f) vga_wseq(cinfo->regbase, CL_SEQR1F, cirrusfb_board_info[btype].sr1f); - ret = cirrusfb_register(info); - if (!ret) - return 0; + error = cirrusfb_register(info); + if (error) { + dev_err(info->device, "Failed to register device, error %d\n", + error); + goto err_unmap_ram; + } - if (btype == BT_PICASSO4 || board_addr > 0x01000000) + zorro_set_drvdata(z, info); + return 0; + +err_unmap_ram: + if (rambase > 16 * MB_) iounmap(info->screen_base); -err_unmap_regbase: - if (btype == BT_PICASSO4) - iounmap(cinfo->regbase - 0x600000); -err_release_region: - release_region(board_addr, board_size); +err_unmap_reg: + if (regbase > 16 * MB_) + iounmap(cinfo->regbase); +err_release_dev: + zorro_release_device(z); err_release_fb: framebuffer_release(info); -err_out: - return ret; + return error; } void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) @@ -2338,6 +2357,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) struct fb_info *info = zorro_get_drvdata(z); cirrusfb_cleanup(info); + zorro_set_drvdata(z, NULL); } static struct zorro_driver cirrusfb_zorro_driver = { diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 93317b5b8740..a122d9287d16 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -25,14 +25,13 @@ #include <asm/system.h> #include <asm/page.h> #include <asm/pgtable.h> +#include <asm/gio_device.h> + #include <video/newport.h> #include <linux/linux_logo.h> #include <linux/font.h> - -extern unsigned long sgi_gfxaddr; - #define FONT_DATA ((unsigned char *)font_vga_8x16.data) /* borrowed from fbcon.c */ @@ -304,12 +303,6 @@ static const char *newport_startup(void) { int i; - if (!sgi_gfxaddr) - return NULL; - - if (!npregs) - npregs = (struct newport_regs *)/* ioremap cannot fail */ - ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); npregs->cset.config = NPORT_CFG_GD0; if (newport_wait(npregs)) @@ -743,26 +736,58 @@ const struct consw newport_con = { .con_save_screen = DUMMY }; -#ifdef MODULE -static int __init newport_console_init(void) +static int newport_probe(struct gio_device *dev, + const struct gio_device_id *id) { - if (!sgi_gfxaddr) - return 0; + unsigned long newport_addr; - if (!npregs) - npregs = (struct newport_regs *)/* ioremap cannot fail */ - ioremap(sgi_gfxaddr, sizeof(struct newport_regs)); + if (!dev->resource.start) + return -EINVAL; + + if (npregs) + return -EBUSY; /* we only support one Newport as console */ + + newport_addr = dev->resource.start + 0xF0000; + if (!request_mem_region(newport_addr, 0x10000, "Newport")) + return -ENODEV; + + npregs = (struct newport_regs *)/* ioremap cannot fail */ + ioremap(newport_addr, sizeof(struct newport_regs)); return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); } -module_init(newport_console_init); -static void __exit newport_console_exit(void) +static void newport_remove(struct gio_device *dev) { give_up_console(&newport_con); iounmap((void *)npregs); } + +static struct gio_device_id newport_ids[] = { + { .id = 0x7e }, + { .id = 0xff } +}; + +MODULE_ALIAS("gio:7e"); + +static struct gio_driver newport_driver = { + .name = "newport", + .id_table = newport_ids, + .probe = newport_probe, + .remove = newport_remove, +}; + +int __init newport_console_init(void) +{ + return gio_register_driver(&newport_driver); +} + +void __exit newport_console_exit(void) +{ + gio_unregister_driver(&newport_driver); +} + +module_init(newport_console_init); module_exit(newport_console_exit); -#endif MODULE_LICENSE("GPL"); diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 7b2c40abae15..0c189b32a4c5 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -420,7 +420,7 @@ static int __init init_control(struct fb_info_control *p) /* Try to pick a video mode out of NVRAM if we have one. */ #ifdef CONFIG_NVRAM - if (default_cmode == CMODE_NVRAM){ + if (default_cmode == CMODE_NVRAM) { cmode = nvram_read_byte(NV_CMODE); if(cmode < CMODE_8 || cmode > CMODE_32) cmode = CMODE_8; diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig deleted file mode 100644 index f99af931d4f8..000000000000 --- a/drivers/video/display/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# -# Display drivers configuration -# - -menu "Display device support" - -config DISPLAY_SUPPORT - tristate "Display panel/monitor support" - ---help--- - This framework adds support for low-level control of a display. - This includes support for power. - - Enable this to be able to choose the drivers for controlling the - physical display panel/monitor on some platforms. This not only - covers LCD displays for PDAs but also other types of displays - such as CRT, TVout etc. - - To have support for your specific display panel you will have to - select the proper drivers which depend on this option. - -comment "Display hardware drivers" - depends on DISPLAY_SUPPORT - -endmenu diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile deleted file mode 100644 index c0ea832bf171..000000000000 --- a/drivers/video/display/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# Display drivers - -display-objs := display-sysfs.o - -obj-$(CONFIG_DISPLAY_SUPPORT) += display.o - diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c deleted file mode 100644 index 0c647d7af0ee..000000000000 --- a/drivers/video/display/display-sysfs.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * display-sysfs.c - Display output driver sysfs interface - * - * Copyright (C) 2007 James Simmons <jsimmons@infradead.org> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/module.h> -#include <linux/display.h> -#include <linux/ctype.h> -#include <linux/idr.h> -#include <linux/err.h> -#include <linux/kdev_t.h> -#include <linux/slab.h> - -static ssize_t display_show_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name); -} - -static ssize_t display_show_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type); -} - -static ssize_t display_show_contrast(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - ssize_t rc = -ENXIO; - - mutex_lock(&dsp->lock); - if (likely(dsp->driver) && dsp->driver->get_contrast) - rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp)); - mutex_unlock(&dsp->lock); - return rc; -} - -static ssize_t display_store_contrast(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct display_device *dsp = dev_get_drvdata(dev); - ssize_t ret = -EINVAL, size; - int contrast; - char *endp; - - contrast = simple_strtoul(buf, &endp, 0); - size = endp - buf; - - if (isspace(*endp)) - size++; - - if (size != count) - return ret; - - mutex_lock(&dsp->lock); - if (likely(dsp->driver && dsp->driver->set_contrast)) { - pr_debug("display: set contrast to %d\n", contrast); - dsp->driver->set_contrast(dsp, contrast); - ret = count; - } - mutex_unlock(&dsp->lock); - return ret; -} - -static ssize_t display_show_max_contrast(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct display_device *dsp = dev_get_drvdata(dev); - ssize_t rc = -ENXIO; - - mutex_lock(&dsp->lock); - if (likely(dsp->driver)) - rc = sprintf(buf, "%d\n", dsp->driver->max_contrast); - mutex_unlock(&dsp->lock); - return rc; -} - -static struct device_attribute display_attrs[] = { - __ATTR(name, S_IRUGO, display_show_name, NULL), - __ATTR(type, S_IRUGO, display_show_type, NULL), - __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast), - __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL), -}; - -static int display_suspend(struct device *dev, pm_message_t state) -{ - struct display_device *dsp = dev_get_drvdata(dev); - - mutex_lock(&dsp->lock); - if (likely(dsp->driver->suspend)) - dsp->driver->suspend(dsp, state); - mutex_unlock(&dsp->lock); - return 0; -}; - -static int display_resume(struct device *dev) -{ - struct display_device *dsp = dev_get_drvdata(dev); - - mutex_lock(&dsp->lock); - if (likely(dsp->driver->resume)) - dsp->driver->resume(dsp); - mutex_unlock(&dsp->lock); - return 0; -}; - -static struct mutex allocated_dsp_lock; -static DEFINE_IDR(allocated_dsp); -static struct class *display_class; - -struct display_device *display_device_register(struct display_driver *driver, - struct device *parent, void *devdata) -{ - struct display_device *new_dev = NULL; - int ret = -EINVAL; - - if (unlikely(!driver)) - return ERR_PTR(ret); - - mutex_lock(&allocated_dsp_lock); - ret = idr_pre_get(&allocated_dsp, GFP_KERNEL); - mutex_unlock(&allocated_dsp_lock); - if (!ret) - return ERR_PTR(ret); - - new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL); - if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) { - // Reserve the index for this display - mutex_lock(&allocated_dsp_lock); - ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx); - mutex_unlock(&allocated_dsp_lock); - - if (!ret) { - new_dev->dev = device_create(display_class, parent, - MKDEV(0, 0), new_dev, - "display%d", new_dev->idx); - if (!IS_ERR(new_dev->dev)) { - new_dev->parent = parent; - new_dev->driver = driver; - mutex_init(&new_dev->lock); - return new_dev; - } - mutex_lock(&allocated_dsp_lock); - idr_remove(&allocated_dsp, new_dev->idx); - mutex_unlock(&allocated_dsp_lock); - ret = -EINVAL; - } - } - kfree(new_dev); - return ERR_PTR(ret); -} -EXPORT_SYMBOL(display_device_register); - -void display_device_unregister(struct display_device *ddev) -{ - if (!ddev) - return; - // Free device - mutex_lock(&ddev->lock); - device_unregister(ddev->dev); - mutex_unlock(&ddev->lock); - // Mark device index as available - mutex_lock(&allocated_dsp_lock); - idr_remove(&allocated_dsp, ddev->idx); - mutex_unlock(&allocated_dsp_lock); - kfree(ddev); -} -EXPORT_SYMBOL(display_device_unregister); - -static int __init display_class_init(void) -{ - display_class = class_create(THIS_MODULE, "display"); - if (IS_ERR(display_class)) { - printk(KERN_ERR "Failed to create display class\n"); - display_class = NULL; - return -EINVAL; - } - display_class->dev_attrs = display_attrs; - display_class->suspend = display_suspend; - display_class->resume = display_resume; - mutex_init(&allocated_dsp_lock); - return 0; -} - -static void __exit display_class_exit(void) -{ - class_destroy(display_class); -} - -module_init(display_class_init); -module_exit(display_class_exit); - -MODULE_DESCRIPTION("Display Hardware handling"); -MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ad936295d8f4..ac9141b85356 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -967,6 +967,20 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { u32 activate = var->activate; + /* When using FOURCC mode, make sure the red, green, blue and + * transp fields are set to 0. + */ + if ((info->fix.capabilities & FB_CAP_FOURCC) && + var->grayscale > 1) { + if (var->red.offset || var->green.offset || + var->blue.offset || var->transp.offset || + var->red.length || var->green.length || + var->blue.length || var->transp.length || + var->red.msb_right || var->green.msb_right || + var->blue.msb_right || var->transp.msb_right) + return -EINVAL; + } + if (!info->fbops->fb_check_var) { *var = info->var; goto done; diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index a16beeb5f548..acf292bfba02 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -36,8 +36,7 @@ #include <linux/fsl-diu-fb.h> #include "edid.h" -#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ - /* 1 for plane 0, 2 for plane 1&2 each */ +#define NUM_AOIS 5 /* 1 for plane 0, 2 for planes 1 & 2 each */ /* HW cursor parameters */ #define MAX_CURS 32 @@ -49,12 +48,6 @@ #define INT_PARERR 0x08 /* Display parameters error interrupt */ #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ -struct diu_addr { - void *vaddr; /* Virtual address */ - dma_addr_t paddr; /* Physical address */ - __u32 offset; -}; - /* * List of supported video modes * @@ -330,23 +323,6 @@ static unsigned int d_cache_line_size; static DEFINE_SPINLOCK(diu_lock); -struct fsl_diu_data { - struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; - /*FSL_AOI_NUM has one dummy AOI */ - struct device_attribute dev_attr; - struct diu_ad *dummy_ad; - void *dummy_aoi_virt; - unsigned int irq; - int fb_enabled; - enum fsl_diu_monitor_port monitor_port; - struct diu __iomem *diu_reg; - spinlock_t reg_lock; - struct diu_addr ad; - struct diu_addr gamma; - struct diu_addr pallete; - struct diu_addr cursor; -}; - enum mfb_index { PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */ PLANE1_AOI0, /* Plane 1, first AOI */ @@ -370,6 +346,42 @@ struct mfb_info { u8 *edid_data; }; +/** + * struct fsl_diu_data - per-DIU data structure + * @dma_addr: DMA address of this structure + * @fsl_diu_info: fb_info objects, one per AOI + * @dev_attr: sysfs structure + * @irq: IRQ + * @monitor_port: the monitor port this DIU is connected to + * @diu_reg: pointer to the DIU hardware registers + * @reg_lock: spinlock for register access + * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI + * dummy_ad: DIU Area Descriptor for the dummy AOI + * @ad[]: Area Descriptors for each real AOI + * @gamma: gamma color table + * @cursor: hardware cursor data + * + * This data structure must be allocated with 32-byte alignment, so that the + * internal fields can be aligned properly. + */ +struct fsl_diu_data { + dma_addr_t dma_addr; + struct fb_info fsl_diu_info[NUM_AOIS]; + struct mfb_info mfb[NUM_AOIS]; + struct device_attribute dev_attr; + unsigned int irq; + enum fsl_diu_monitor_port monitor_port; + struct diu __iomem *diu_reg; + spinlock_t reg_lock; + u8 dummy_aoi[4 * 4 * 4]; + struct diu_ad dummy_ad __aligned(8); + struct diu_ad ad[NUM_AOIS] __aligned(8); + u8 gamma[256 * 3] __aligned(32); + u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); +} __aligned(32); + +/* Determine the DMA address of a member of the fsl_diu_data structure */ +#define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f)) static struct mfb_info mfb_template[] = { { @@ -449,37 +461,6 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) return diu_ops.valid_monitor_port(port); } -/** - * fsl_diu_alloc - allocate memory for the DIU - * @size: number of bytes to allocate - * @param: returned physical address of memory - * - * This function allocates a physically-contiguous block of memory. - */ -static void *fsl_diu_alloc(size_t size, phys_addr_t *phys) -{ - void *virt; - - virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO); - if (virt) - *phys = virt_to_phys(virt); - - return virt; -} - -/** - * fsl_diu_free - release DIU memory - * @virt: pointer returned by fsl_diu_alloc() - * @size: number of bytes allocated by fsl_diu_alloc() - * - * This function releases memory allocated by fsl_diu_alloc(). - */ -static void fsl_diu_free(void *virt, size_t size) -{ - if (virt && size) - free_pages_exact(virt, size); -} - /* * Workaround for failed writing desc register of planes. * Needed with MPC5121 DIU rev 2.0 silicon. @@ -495,8 +476,8 @@ static void fsl_diu_enable_panel(struct fb_info *info) { struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; struct diu_ad *ad = mfbi->ad; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; switch (mfbi->index) { case PLANE0: @@ -504,7 +485,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) wr_reg_wa(&hw->desc[0], ad->paddr); break; case PLANE1_AOI0: - cmfbi = machine_data->fsl_diu_info[2]->par; + cmfbi = &data->mfb[2]; if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ if (cmfbi->count > 0) /* AOI1 open */ ad->next_ad = @@ -515,7 +496,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) } break; case PLANE2_AOI0: - cmfbi = machine_data->fsl_diu_info[4]->par; + cmfbi = &data->mfb[4]; if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ if (cmfbi->count > 0) /* AOI1 open */ ad->next_ad = @@ -526,17 +507,17 @@ static void fsl_diu_enable_panel(struct fb_info *info) } break; case PLANE1_AOI1: - pmfbi = machine_data->fsl_diu_info[1]->par; + pmfbi = &data->mfb[1]; ad->next_ad = 0; - if (hw->desc[1] == machine_data->dummy_ad->paddr) + if (hw->desc[1] == data->dummy_ad.paddr) wr_reg_wa(&hw->desc[1], ad->paddr); else /* AOI0 open */ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); break; case PLANE2_AOI1: - pmfbi = machine_data->fsl_diu_info[3]->par; + pmfbi = &data->mfb[3]; ad->next_ad = 0; - if (hw->desc[2] == machine_data->dummy_ad->paddr) + if (hw->desc[2] == data->dummy_ad.paddr) wr_reg_wa(&hw->desc[2], ad->paddr); else /* AOI0 was open */ pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); @@ -548,52 +529,52 @@ static void fsl_diu_disable_panel(struct fb_info *info) { struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; struct diu_ad *ad = mfbi->ad; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; switch (mfbi->index) { case PLANE0: - if (hw->desc[0] != machine_data->dummy_ad->paddr) - wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr); + if (hw->desc[0] != data->dummy_ad.paddr) + wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr); break; case PLANE1_AOI0: - cmfbi = machine_data->fsl_diu_info[2]->par; + cmfbi = &data->mfb[2]; if (cmfbi->count > 0) /* AOI1 is open */ wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); /* move AOI1 to the first */ else /* AOI1 was closed */ - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); /* close AOI 0 */ break; case PLANE2_AOI0: - cmfbi = machine_data->fsl_diu_info[4]->par; + cmfbi = &data->mfb[4]; if (cmfbi->count > 0) /* AOI1 is open */ wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); /* move AOI1 to the first */ else /* AOI1 was closed */ - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); /* close AOI 0 */ break; case PLANE1_AOI1: - pmfbi = machine_data->fsl_diu_info[1]->par; + pmfbi = &data->mfb[1]; if (hw->desc[1] != ad->paddr) { /* AOI1 is not the first in the chain */ if (pmfbi->count > 0) /* AOI0 is open, must be the first */ pmfbi->ad->next_ad = 0; } else /* AOI1 is the first in the chain */ - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); /* close AOI 1 */ break; case PLANE2_AOI1: - pmfbi = machine_data->fsl_diu_info[3]->par; + pmfbi = &data->mfb[3]; if (hw->desc[2] != ad->paddr) { /* AOI1 is not the first in the chain */ if (pmfbi->count > 0) /* AOI0 is open, must be the first */ pmfbi->ad->next_ad = 0; } else /* AOI1 is the first in the chain */ - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); + wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); /* close AOI 1 */ break; } @@ -602,39 +583,33 @@ static void fsl_diu_disable_panel(struct fb_info *info) static void enable_lcdc(struct fb_info *info) { struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; - if (!machine_data->fb_enabled) { - out_be32(&hw->diu_mode, MFB_MODE1); - machine_data->fb_enabled++; - } + out_be32(&hw->diu_mode, MFB_MODE1); } static void disable_lcdc(struct fb_info *info) { struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; - struct diu __iomem *hw = machine_data->diu_reg; + struct fsl_diu_data *data = mfbi->parent; + struct diu __iomem *hw = data->diu_reg; - if (machine_data->fb_enabled) { - out_be32(&hw->diu_mode, 0); - machine_data->fb_enabled = 0; - } + out_be32(&hw->diu_mode, 0); } static void adjust_aoi_size_position(struct fb_var_screeninfo *var, struct fb_info *info) { struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; + struct fsl_diu_data *data = mfbi->parent; int available_height, upper_aoi_bottom; enum mfb_index index = mfbi->index; int lower_aoi_is_open, upper_aoi_is_open; __u32 base_plane_width, base_plane_height, upper_aoi_height; - base_plane_width = machine_data->fsl_diu_info[0]->var.xres; - base_plane_height = machine_data->fsl_diu_info[0]->var.yres; + base_plane_width = data->fsl_diu_info[0].var.xres; + base_plane_height = data->fsl_diu_info[0].var.yres; if (mfbi->x_aoi_d < 0) mfbi->x_aoi_d = 0; @@ -649,7 +624,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, break; case PLANE1_AOI0: case PLANE2_AOI0: - lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; + lower_aoi_mfbi = data->fsl_diu_info[index+1].par; lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; if (var->xres > base_plane_width) var->xres = base_plane_width; @@ -667,9 +642,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, break; case PLANE1_AOI1: case PLANE2_AOI1: - upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; - upper_aoi_height = - machine_data->fsl_diu_info[index-1]->var.yres; + upper_aoi_mfbi = data->fsl_diu_info[index-1].par; + upper_aoi_height = data->fsl_diu_info[index-1].var.yres; upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; if (var->xres > base_plane_width) @@ -809,33 +783,33 @@ static void update_lcdc(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; + struct fsl_diu_data *data = mfbi->parent; struct diu __iomem *hw; int i, j; - char __iomem *cursor_base, *gamma_table_base; + u8 *gamma_table_base; u32 temp; - hw = machine_data->diu_reg; + hw = data->diu_reg; + + diu_ops.set_monitor_port(data->monitor_port); + gamma_table_base = data->gamma; - diu_ops.set_monitor_port(machine_data->monitor_port); - gamma_table_base = machine_data->gamma.vaddr; - cursor_base = machine_data->cursor.vaddr; /* Prep for DIU init - gamma table, cursor table */ for (i = 0; i <= 2; i++) for (j = 0; j <= 255; j++) *gamma_table_base++ = j; - diu_ops.set_gamma_table(machine_data->monitor_port, - machine_data->gamma.vaddr); + if (diu_ops.set_gamma_table) + diu_ops.set_gamma_table(data->monitor_port, data->gamma); disable_lcdc(info); /* Program DIU registers */ - out_be32(&hw->gamma, machine_data->gamma.paddr); - out_be32(&hw->cursor, machine_data->cursor.paddr); + out_be32(&hw->gamma, DMA_ADDR(data, gamma)); + out_be32(&hw->cursor, DMA_ADDR(data, cursor)); out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ @@ -870,16 +844,17 @@ static void update_lcdc(struct fb_info *info) static int map_video_memory(struct fb_info *info) { - phys_addr_t phys; u32 smem_len = info->fix.line_length * info->var.yres_virtual; + void *p; - info->screen_base = fsl_diu_alloc(smem_len, &phys); - if (info->screen_base == NULL) { + p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO); + if (!p) { dev_err(info->dev, "unable to allocate fb memory\n"); return -ENOMEM; } mutex_lock(&info->mm_lock); - info->fix.smem_start = (unsigned long) phys; + info->screen_base = p; + info->fix.smem_start = virt_to_phys(info->screen_base); info->fix.smem_len = smem_len; mutex_unlock(&info->mm_lock); info->screen_size = info->fix.smem_len; @@ -889,12 +864,17 @@ static int map_video_memory(struct fb_info *info) static void unmap_video_memory(struct fb_info *info) { - fsl_diu_free(info->screen_base, info->fix.smem_len); + void *p = info->screen_base; + size_t l = info->fix.smem_len; + mutex_lock(&info->mm_lock); info->screen_base = NULL; info->fix.smem_start = 0; info->fix.smem_len = 0; mutex_unlock(&info->mm_lock); + + if (p) + free_pages_exact(p, l); } /* @@ -913,6 +893,59 @@ static int fsl_diu_set_aoi(struct fb_info *info) return 0; } +/** + * fsl_diu_get_pixel_format: return the pixel format for a given color depth + * + * The pixel format is a 32-bit value that determine which bits in each + * pixel are to be used for each color. This is the default function used + * if the platform does not define its own version. + */ +static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel) +{ +#define PF_BYTE_F 0x10000000 +#define PF_ALPHA_C_MASK 0x0E000000 +#define PF_ALPHA_C_SHIFT 25 +#define PF_BLUE_C_MASK 0x01800000 +#define PF_BLUE_C_SHIFT 23 +#define PF_GREEN_C_MASK 0x00600000 +#define PF_GREEN_C_SHIFT 21 +#define PF_RED_C_MASK 0x00180000 +#define PF_RED_C_SHIFT 19 +#define PF_PALETTE 0x00040000 +#define PF_PIXEL_S_MASK 0x00030000 +#define PF_PIXEL_S_SHIFT 16 +#define PF_COMP_3_MASK 0x0000F000 +#define PF_COMP_3_SHIFT 12 +#define PF_COMP_2_MASK 0x00000F00 +#define PF_COMP_2_SHIFT 8 +#define PF_COMP_1_MASK 0x000000F0 +#define PF_COMP_1_SHIFT 4 +#define PF_COMP_0_MASK 0x0000000F +#define PF_COMP_0_SHIFT 0 + +#define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \ + cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \ + (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \ + (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \ + (c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \ + (c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT)) + + switch (bits_per_pixel) { + case 32: + /* 0x88883316 */ + return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8); + case 24: + /* 0x88082219 */ + return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8); + case 16: + /* 0x65053118 */ + return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0); + default: + pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel); + return 0; + } +} + /* * Using the fb_var_screeninfo in fb_info we set the resolution of this * particular framebuffer. This function alters the fb_fix_screeninfo stored @@ -926,11 +959,11 @@ static int fsl_diu_set_par(struct fb_info *info) unsigned long len; struct fb_var_screeninfo *var = &info->var; struct mfb_info *mfbi = info->par; - struct fsl_diu_data *machine_data = mfbi->parent; + struct fsl_diu_data *data = mfbi->parent; struct diu_ad *ad = mfbi->ad; struct diu __iomem *hw; - hw = machine_data->diu_reg; + hw = data->diu_reg; set_fix(info); mfbi->cursor_reset = 1; @@ -948,8 +981,12 @@ static int fsl_diu_set_par(struct fb_info *info) } } - ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port, - var->bits_per_pixel); + if (diu_ops.get_pixel_format) + ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port, + var->bits_per_pixel); + else + ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel); + ad->addr = cpu_to_le32(info->fix.smem_start); ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | var->xres_virtual) | mfbi->g_alpha; @@ -1208,21 +1245,6 @@ static struct fb_ops fsl_diu_ops = { .fb_release = fsl_diu_release, }; -static int init_fbinfo(struct fb_info *info) -{ - struct mfb_info *mfbi = info->par; - - info->device = NULL; - info->var.activate = FB_ACTIVATE_NOW; - info->fbops = &fsl_diu_ops; - info->flags = FBINFO_FLAG_DEFAULT; - info->pseudo_palette = &mfbi->pseudo_palette; - - /* Allocate colormap */ - fb_alloc_cmap(&info->cmap, 16, 0); - return 0; -} - static int __devinit install_fb(struct fb_info *info) { int rc; @@ -1232,8 +1254,15 @@ static int __devinit install_fb(struct fb_info *info) unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); int has_default_mode = 1; - if (init_fbinfo(info)) - return -EINVAL; + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_diu_ops; + info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK | + FBINFO_READS_FAST; + info->pseudo_palette = mfbi->pseudo_palette; + + rc = fb_alloc_cmap(&info->cmap, 16, 0); + if (rc) + return rc; if (mfbi->index == PLANE0) { if (mfbi->edid_data) { @@ -1359,16 +1388,16 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id) return IRQ_NONE; } -static int request_irq_local(struct fsl_diu_data *machine_data) +static int request_irq_local(struct fsl_diu_data *data) { - struct diu __iomem *hw = machine_data->diu_reg; + struct diu __iomem *hw = data->diu_reg; u32 ints; int ret; /* Read to clear the status */ in_be32(&hw->int_status); - ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); + ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); if (!ret) { ints = INT_PARERR | INT_LS_BF_VS; #if !defined(CONFIG_NOT_COHERENT_CACHE) @@ -1383,14 +1412,14 @@ static int request_irq_local(struct fsl_diu_data *machine_data) return ret; } -static void free_irq_local(struct fsl_diu_data *machine_data) +static void free_irq_local(struct fsl_diu_data *data) { - struct diu __iomem *hw = machine_data->diu_reg; + struct diu __iomem *hw = data->diu_reg; /* Disable all LCDC interrupt */ out_be32(&hw->int_mask, 0x1f); - free_irq(machine_data->irq, NULL); + free_irq(data->irq, NULL); } #ifdef CONFIG_PM @@ -1400,20 +1429,20 @@ static void free_irq_local(struct fsl_diu_data *machine_data) */ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) { - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; - machine_data = dev_get_drvdata(&ofdev->dev); - disable_lcdc(machine_data->fsl_diu_info[0]); + data = dev_get_drvdata(&ofdev->dev); + disable_lcdc(data->fsl_diu_info[0]); return 0; } static int fsl_diu_resume(struct platform_device *ofdev) { - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; - machine_data = dev_get_drvdata(&ofdev->dev); - enable_lcdc(machine_data->fsl_diu_info[0]); + data = dev_get_drvdata(&ofdev->dev); + enable_lcdc(data->fsl_diu_info[0]); return 0; } @@ -1423,56 +1452,24 @@ static int fsl_diu_resume(struct platform_device *ofdev) #define fsl_diu_resume NULL #endif /* CONFIG_PM */ -/* Align to 64-bit(8-byte), 32-byte, etc. */ -static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, - u32 bytes_align) -{ - u32 offset; - dma_addr_t mask; - - buf->vaddr = - dma_alloc_coherent(dev, size + bytes_align, &buf->paddr, - GFP_DMA | __GFP_ZERO); - if (!buf->vaddr) - return -ENOMEM; - - mask = bytes_align - 1; - offset = buf->paddr & mask; - if (offset) { - buf->offset = bytes_align - offset; - buf->paddr = buf->paddr + offset; - } else - buf->offset = 0; - - return 0; -} - -static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, - u32 bytes_align) -{ - dma_free_coherent(dev, size + bytes_align, buf->vaddr, - buf->paddr - buf->offset); -} - static ssize_t store_monitor(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { enum fsl_diu_monitor_port old_monitor_port; - struct fsl_diu_data *machine_data = + struct fsl_diu_data *data = container_of(attr, struct fsl_diu_data, dev_attr); - old_monitor_port = machine_data->monitor_port; - machine_data->monitor_port = fsl_diu_name_to_port(buf); + old_monitor_port = data->monitor_port; + data->monitor_port = fsl_diu_name_to_port(buf); - if (old_monitor_port != machine_data->monitor_port) { + if (old_monitor_port != data->monitor_port) { /* All AOIs need adjust pixel format * fsl_diu_set_par only change the pixsel format here * unlikely to fail. */ - fsl_diu_set_par(machine_data->fsl_diu_info[0]); - fsl_diu_set_par(machine_data->fsl_diu_info[1]); - fsl_diu_set_par(machine_data->fsl_diu_info[2]); - fsl_diu_set_par(machine_data->fsl_diu_info[3]); - fsl_diu_set_par(machine_data->fsl_diu_info[4]); + unsigned int i; + + for (i=0; i < NUM_AOIS; i++) + fsl_diu_set_par(&data->fsl_diu_info[i]); } return count; } @@ -1480,10 +1477,10 @@ static ssize_t store_monitor(struct device *device, static ssize_t show_monitor(struct device *device, struct device_attribute *attr, char *buf) { - struct fsl_diu_data *machine_data = + struct fsl_diu_data *data = container_of(attr, struct fsl_diu_data, dev_attr); - switch (machine_data->monitor_port) { + switch (data->monitor_port) { case FSL_DIU_PORT_DVI: return sprintf(buf, "DVI\n"); case FSL_DIU_PORT_LVDS: @@ -1499,28 +1496,52 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct mfb_info *mfbi; - phys_addr_t dummy_ad_addr = 0; - int ret, i, error = 0; - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; int diu_mode; + dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */ + unsigned int i; + int ret; - machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); - if (!machine_data) + data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), + &dma_addr, GFP_DMA | __GFP_ZERO); + if (!data) return -ENOMEM; + data->dma_addr = dma_addr; + + /* + * dma_alloc_coherent() uses a page allocator, so the address is + * always page-aligned. We need the memory to be 32-byte aligned, + * so that's good. However, if one day the allocator changes, we + * need to catch that. It's not worth the effort to handle unaligned + * alloctions now because it's highly unlikely to ever be a problem. + */ + if ((unsigned long)data & 31) { + dev_err(&pdev->dev, "misaligned allocation"); + ret = -ENOMEM; + goto error; + } - spin_lock_init(&machine_data->reg_lock); + spin_lock_init(&data->reg_lock); - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { - machine_data->fsl_diu_info[i] = - framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); - if (!machine_data->fsl_diu_info[i]) { - dev_err(&pdev->dev, "cannot allocate memory\n"); - ret = -ENOMEM; - goto error2; - } - mfbi = machine_data->fsl_diu_info[i]->par; + for (i = 0; i < NUM_AOIS; i++) { + struct fb_info *info = &data->fsl_diu_info[i]; + + info->device = &pdev->dev; + info->par = &data->mfb[i]; + + /* + * We store the physical address of the AD in the reserved + * 'paddr' field of the AD itself. + */ + data->ad[i].paddr = DMA_ADDR(data, ad[i]); + + info->fix.smem_start = 0; + + /* Initialize the AOI data structure */ + mfbi = info->par; memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); - mfbi->parent = machine_data; + mfbi->parent = data; + mfbi->ad = &data->ad[i]; if (mfbi->index == PLANE0) { const u8 *prop; @@ -1534,158 +1555,102 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) } } - machine_data->diu_reg = of_iomap(np, 0); - if (!machine_data->diu_reg) { + data->diu_reg = of_iomap(np, 0); + if (!data->diu_reg) { dev_err(&pdev->dev, "cannot map DIU registers\n"); ret = -EFAULT; - goto error2; + goto error; } - diu_mode = in_be32(&machine_data->diu_reg->diu_mode); + diu_mode = in_be32(&data->diu_reg->diu_mode); if (diu_mode == MFB_MODE0) - out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */ + out_be32(&data->diu_reg->diu_mode, 0); /* disable DIU */ /* Get the IRQ of the DIU */ - machine_data->irq = irq_of_parse_and_map(np, 0); + data->irq = irq_of_parse_and_map(np, 0); - if (!machine_data->irq) { + if (!data->irq) { dev_err(&pdev->dev, "could not get DIU IRQ\n"); ret = -EINVAL; goto error; } - machine_data->monitor_port = monitor_port; - - /* Area descriptor memory pool aligns to 64-bit boundary */ - if (allocate_buf(&pdev->dev, &machine_data->ad, - sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) - return -ENOMEM; - - /* Get memory for Gamma Table - 32-byte aligned memory */ - if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) { - ret = -ENOMEM; - goto error; - } - - /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ - if (allocate_buf(&pdev->dev, &machine_data->cursor, - MAX_CURS * MAX_CURS * 2, 32)) { - ret = -ENOMEM; - goto error; - } - - i = ARRAY_SIZE(machine_data->fsl_diu_info); - machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr + - machine_data->ad.offset) + i; - machine_data->dummy_ad->paddr = machine_data->ad.paddr + - i * sizeof(struct diu_ad); - machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); - if (!machine_data->dummy_aoi_virt) { - ret = -ENOMEM; - goto error; - } - machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); - machine_data->dummy_ad->pix_fmt = 0x88882317; - machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); - machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); - machine_data->dummy_ad->offset_xyi = 0; - machine_data->dummy_ad->offset_xyd = 0; - machine_data->dummy_ad->next_ad = 0; + data->monitor_port = monitor_port; + + /* Initialize the dummy Area Descriptor */ + data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi)); + data->dummy_ad.pix_fmt = 0x88882317; + data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4); + data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2); + data->dummy_ad.offset_xyi = 0; + data->dummy_ad.offset_xyd = 0; + data->dummy_ad.next_ad = 0; + data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad); /* * Let DIU display splash screen if it was pre-initialized * by the bootloader, set dummy area descriptor otherwise. */ if (diu_mode == MFB_MODE0) - out_be32(&machine_data->diu_reg->desc[0], - machine_data->dummy_ad->paddr); - - out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr); - out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr); - - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { - machine_data->fsl_diu_info[i]->fix.smem_start = 0; - mfbi = machine_data->fsl_diu_info[i]->par; - mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr - + machine_data->ad.offset) + i; - mfbi->ad->paddr = - machine_data->ad.paddr + i * sizeof(struct diu_ad); - ret = install_fb(machine_data->fsl_diu_info[i]); + out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr); + + out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr); + out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr); + + for (i = 0; i < NUM_AOIS; i++) { + ret = install_fb(&data->fsl_diu_info[i]); if (ret) { dev_err(&pdev->dev, "could not register fb %d\n", i); goto error; } } - if (request_irq_local(machine_data)) { + if (request_irq_local(data)) { dev_err(&pdev->dev, "could not claim irq\n"); goto error; } - sysfs_attr_init(&machine_data->dev_attr.attr); - machine_data->dev_attr.attr.name = "monitor"; - machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; - machine_data->dev_attr.show = show_monitor; - machine_data->dev_attr.store = store_monitor; - error = device_create_file(machine_data->fsl_diu_info[0]->dev, - &machine_data->dev_attr); - if (error) { + sysfs_attr_init(&data->dev_attr.attr); + data->dev_attr.attr.name = "monitor"; + data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; + data->dev_attr.show = show_monitor; + data->dev_attr.store = store_monitor; + ret = device_create_file(&pdev->dev, &data->dev_attr); + if (ret) { dev_err(&pdev->dev, "could not create sysfs file %s\n", - machine_data->dev_attr.attr.name); + data->dev_attr.attr.name); } - dev_set_drvdata(&pdev->dev, machine_data); + dev_set_drvdata(&pdev->dev, data); return 0; error: - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - uninstall_fb(machine_data->fsl_diu_info[i]); - - if (machine_data->ad.vaddr) - free_buf(&pdev->dev, &machine_data->ad, - sizeof(struct diu_ad) * FSL_AOI_NUM, 8); - if (machine_data->gamma.vaddr) - free_buf(&pdev->dev, &machine_data->gamma, 768, 32); - if (machine_data->cursor.vaddr) - free_buf(&pdev->dev, &machine_data->cursor, - MAX_CURS * MAX_CURS * 2, 32); - if (machine_data->dummy_aoi_virt) - fsl_diu_free(machine_data->dummy_aoi_virt, 64); - iounmap(machine_data->diu_reg); - -error2: - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - if (machine_data->fsl_diu_info[i]) - framebuffer_release(machine_data->fsl_diu_info[i]); - kfree(machine_data); + for (i = 0; i < NUM_AOIS; i++) + uninstall_fb(&data->fsl_diu_info[i]); + + iounmap(data->diu_reg); + + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, + data->dma_addr); return ret; } static int fsl_diu_remove(struct platform_device *pdev) { - struct fsl_diu_data *machine_data; + struct fsl_diu_data *data; int i; - machine_data = dev_get_drvdata(&pdev->dev); - disable_lcdc(machine_data->fsl_diu_info[0]); - free_irq_local(machine_data); - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - uninstall_fb(machine_data->fsl_diu_info[i]); - if (machine_data->ad.vaddr) - free_buf(&pdev->dev, &machine_data->ad, - sizeof(struct diu_ad) * FSL_AOI_NUM, 8); - if (machine_data->gamma.vaddr) - free_buf(&pdev->dev, &machine_data->gamma, 768, 32); - if (machine_data->cursor.vaddr) - free_buf(&pdev->dev, &machine_data->cursor, - MAX_CURS * MAX_CURS * 2, 32); - if (machine_data->dummy_aoi_virt) - fsl_diu_free(machine_data->dummy_aoi_virt, 64); - iounmap(machine_data->diu_reg); - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) - if (machine_data->fsl_diu_info[i]) - framebuffer_release(machine_data->fsl_diu_info[i]); - kfree(machine_data); + data = dev_get_drvdata(&pdev->dev); + disable_lcdc(&data->fsl_diu_info[0]); + free_irq_local(data); + + for (i = 0; i < NUM_AOIS; i++) + uninstall_fb(&data->fsl_diu_info[i]); + + iounmap(data->diu_reg); + + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, + data->dma_addr); return 0; } diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c index f37e02538203..da066c210923 100644 --- a/drivers/video/grvga.c +++ b/drivers/video/grvga.c @@ -70,7 +70,7 @@ static const struct fb_videomode grvga_modedb[] = { } }; -static struct fb_fix_screeninfo grvga_fix __initdata = { +static struct fb_fix_screeninfo grvga_fix __devinitdata = { .id = "AG SVGACTRL", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, @@ -267,7 +267,7 @@ static struct fb_ops grvga_ops = { .fb_imageblit = cfb_imageblit }; -static int __init grvga_parse_custom(char *options, +static int __devinit grvga_parse_custom(char *options, struct fb_var_screeninfo *screendata) { char *this_opt; diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 4394389caf68..c645f9282650 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -133,7 +133,7 @@ static struct fb_fix_screeninfo hga_fix __devinitdata = { /* Don't assume that tty1 will be the initial current console. */ static int release_io_port = 0; static int release_io_ports = 0; -static int nologo = 0; +static bool nologo = 0; /* ------------------------------------------------------------------------- * diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 318f6fb895b2..b83f36190cae 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -135,8 +135,8 @@ static struct pci_driver i810fb_driver = { static char *mode_option __devinitdata = NULL; static int vram __devinitdata = 4; static int bpp __devinitdata = 8; -static int mtrr __devinitdata; -static int accel __devinitdata; +static bool mtrr __devinitdata; +static bool accel __devinitdata; static int hsync1 __devinitdata; static int hsync2 __devinitdata; static int vsync1 __devinitdata; @@ -144,10 +144,10 @@ static int vsync2 __devinitdata; static int xres __devinitdata; static int yres; static int vyres __devinitdata; -static int sync __devinitdata; -static int extvga __devinitdata; -static int dcolor __devinitdata; -static int ddc3 __devinitdata = 2; +static bool sync __devinitdata; +static bool extvga __devinitdata; +static bool dcolor __devinitdata; +static bool ddc3 __devinitdata; /*------------------------------------------------------------*/ @@ -1776,7 +1776,7 @@ static void __devinit i810_init_defaults(struct i810fb_par *par, if (sync) par->dev_flags |= ALWAYS_SYNC; - par->ddc_num = ddc3; + par->ddc_num = (ddc3 ? 3 : 2); if (bpp < 8) bpp = 8; @@ -1999,7 +1999,7 @@ static int __devinit i810fb_setup(char *options) else if (!strncmp(this_opt, "dcolor", 6)) dcolor = 1; else if (!strncmp(this_opt, "ddc3", 4)) - ddc3 = 3; + ddc3 = true; else mode_option = this_opt; } diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 5ba399991050..c6afa33a4532 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -230,15 +230,15 @@ MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS MODULE_LICENSE("Dual BSD/GPL"); MODULE_DEVICE_TABLE(pci, intelfb_pci_table); -static int accel = 1; +static bool accel = 1; static int vram = 4; -static int hwcursor = 0; -static int mtrr = 1; -static int fixed = 0; -static int noinit = 0; -static int noregister = 0; -static int probeonly = 0; -static int idonly = 0; +static bool hwcursor = 0; +static bool mtrr = 1; +static bool fixed = 0; +static bool noinit = 0; +static bool noregister = 0; +static bool probeonly = 0; +static bool idonly = 0; static int bailearly = 0; static int voffset = 48; static char *mode = NULL; @@ -263,7 +263,7 @@ module_param(probeonly, bool, 0); MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)"); module_param(idonly, bool, 0); MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)"); -module_param(bailearly, bool, 0); +module_param(bailearly, int, 0); MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)"); module_param(mode, charp, S_IRUGO); MODULE_PARM_DESC(mode, diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index ea7a8ccc830c..080c35b34bbb 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -21,7 +21,7 @@ #include <asm/bootinfo.h> #endif -static int nologo; +static bool nologo; module_param(nologo, bool, 0); MODULE_PARM_DESC(nologo, "Disables startup logo"); diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 44bf8d4a216b..401a56e250bd 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -147,7 +147,6 @@ static struct fb_var_screeninfo vesafb_defined = { 39721L,48L,16L,33L,10L, 96L,2L,~0, /* No sync info */ FB_VMODE_NONINTERLACED, - 0, {0,0,0,0,0} }; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index d7112c39614b..02796a4317a9 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -593,7 +593,6 @@ static struct fb_var_screeninfo matroxfb_dh_defined = { 39721L,48L,16L,33L,10L, 96L,2,0, /* no sync info */ FB_VMODE_NONINTERLACED, - 0, {0,0,0,0,0} }; static int matroxfb_dh_regit(const struct matrox_fb_info *minfo, diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 6ce34160da78..55bf6196b7a0 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -1053,18 +1053,7 @@ static struct platform_driver mbxfb_driver = { }, }; -int __devinit mbxfb_init(void) -{ - return platform_driver_register(&mbxfb_driver); -} - -static void __devexit mbxfb_exit(void) -{ - platform_driver_unregister(&mbxfb_driver); -} - -module_init(mbxfb_init); -module_exit(mbxfb_exit); +module_platform_driver(mbxfb_driver); MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device"); MODULE_AUTHOR("Mike Rapoport, Compulab"); diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index eb3c5eea1a0f..4a89f889852d 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -902,18 +902,7 @@ static struct platform_driver mxsfb_driver = { }, }; -static int __init mxsfb_init(void) -{ - return platform_driver_register(&mxsfb_driver); -} - -static void __exit mxsfb_exit(void) -{ - platform_driver_unregister(&mxsfb_driver); -} - -module_init(mxsfb_init); -module_exit(mxsfb_exit); +module_platform_driver(mxsfb_driver); MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index feea7b1dc386..fb3f67391105 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -84,11 +84,11 @@ /* --------------------------------------------------------------------- */ -static int internal; -static int external; -static int libretto; -static int nostretch; -static int nopciburst; +static bool internal; +static bool external; +static bool libretto; +static bool nostretch; +static bool nopciburst; static char *mode_option __devinitdata = NULL; #ifdef MODULE diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index d1fbbd888cf4..e10f551ade21 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -762,18 +762,7 @@ static struct platform_driver nuc900fb_driver = { }, }; -int __devinit nuc900fb_init(void) -{ - return platform_driver_register(&nuc900fb_driver); -} - -static void __exit nuc900fb_cleanup(void) -{ - platform_driver_unregister(&nuc900fb_driver); -} - -module_init(nuc900fb_init); -module_exit(nuc900fb_cleanup); +module_platform_driver(nuc900fb_driver); MODULE_DESCRIPTION("Framebuffer driver for the NUC900"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 081dc4745274..fe13ac567d54 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -81,7 +81,7 @@ static int vram __devinitdata = 0; static int bpp __devinitdata = 8; static int reverse_i2c __devinitdata; #ifdef CONFIG_MTRR -static int nomtrr __devinitdata = 0; +static bool nomtrr __devinitdata = false; #endif #ifdef CONFIG_PMAC_BACKLIGHT static int backlight __devinitdata = 1; @@ -1509,7 +1509,7 @@ static int __devinit nvidiafb_setup(char *options) backlight = simple_strtoul(this_opt+10, NULL, 0); #ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { - nomtrr = 1; + nomtrr = true; #endif } else if (!strncmp(this_opt, "fpdither:", 9)) { fpdither = simple_strtol(this_opt+9, NULL, 0); @@ -1599,7 +1599,7 @@ MODULE_PARM_DESC(bpp, "pixel width in bits" module_param(reverse_i2c, int, 0); MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus"); #ifdef CONFIG_MTRR -module_param(nomtrr, bool, 0); +module_param(nomtrr, bool, false); MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) " "(default=0)"); #endif diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c index 6978ae4ef83a..0fdd6f6873bf 100644 --- a/drivers/video/omap/lcd_ams_delta.c +++ b/drivers/video/omap/lcd_ams_delta.c @@ -198,7 +198,7 @@ static int ams_delta_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver ams_delta_panel_driver = { +static struct platform_driver ams_delta_panel_driver = { .probe = ams_delta_panel_probe, .remove = ams_delta_panel_remove, .suspend = ams_delta_panel_suspend, @@ -209,15 +209,4 @@ struct platform_driver ams_delta_panel_driver = { }, }; -static int __init ams_delta_panel_drv_init(void) -{ - return platform_driver_register(&ams_delta_panel_driver); -} - -static void __exit ams_delta_panel_drv_cleanup(void) -{ - platform_driver_unregister(&ams_delta_panel_driver); -} - -module_init(ams_delta_panel_drv_init); -module_exit(ams_delta_panel_drv_cleanup); +module_platform_driver(ams_delta_panel_driver); diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c index 622ad839fd9d..49bdeca81e50 100644 --- a/drivers/video/omap/lcd_h3.c +++ b/drivers/video/omap/lcd_h3.c @@ -113,7 +113,7 @@ static int h3_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver h3_panel_driver = { +static struct platform_driver h3_panel_driver = { .probe = h3_panel_probe, .remove = h3_panel_remove, .suspend = h3_panel_suspend, @@ -124,16 +124,4 @@ struct platform_driver h3_panel_driver = { }, }; -static int __init h3_panel_drv_init(void) -{ - return platform_driver_register(&h3_panel_driver); -} - -static void __exit h3_panel_drv_cleanup(void) -{ - platform_driver_unregister(&h3_panel_driver); -} - -module_init(h3_panel_drv_init); -module_exit(h3_panel_drv_cleanup); - +module_platform_driver(h3_panel_driver); diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c index 4802419da83b..20f477851d54 100644 --- a/drivers/video/omap/lcd_htcherald.c +++ b/drivers/video/omap/lcd_htcherald.c @@ -104,7 +104,7 @@ static int htcherald_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver htcherald_panel_driver = { +static struct platform_driver htcherald_panel_driver = { .probe = htcherald_panel_probe, .remove = htcherald_panel_remove, .suspend = htcherald_panel_suspend, @@ -115,16 +115,4 @@ struct platform_driver htcherald_panel_driver = { }, }; -static int __init htcherald_panel_drv_init(void) -{ - return platform_driver_register(&htcherald_panel_driver); -} - -static void __exit htcherald_panel_drv_cleanup(void) -{ - platform_driver_unregister(&htcherald_panel_driver); -} - -module_init(htcherald_panel_drv_init); -module_exit(htcherald_panel_drv_cleanup); - +module_platform_driver(htcherald_panel_driver); diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c index 3271f1643b26..b38b1dd15ce3 100644 --- a/drivers/video/omap/lcd_inn1510.c +++ b/drivers/video/omap/lcd_inn1510.c @@ -98,7 +98,7 @@ static int innovator1510_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver innovator1510_panel_driver = { +static struct platform_driver innovator1510_panel_driver = { .probe = innovator1510_panel_probe, .remove = innovator1510_panel_remove, .suspend = innovator1510_panel_suspend, @@ -109,16 +109,4 @@ struct platform_driver innovator1510_panel_driver = { }, }; -static int __init innovator1510_panel_drv_init(void) -{ - return platform_driver_register(&innovator1510_panel_driver); -} - -static void __exit innovator1510_panel_drv_cleanup(void) -{ - platform_driver_unregister(&innovator1510_panel_driver); -} - -module_init(innovator1510_panel_drv_init); -module_exit(innovator1510_panel_drv_cleanup); - +module_platform_driver(innovator1510_panel_driver); diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c index 12cc52a70f96..7e8bd8e08a98 100644 --- a/drivers/video/omap/lcd_inn1610.c +++ b/drivers/video/omap/lcd_inn1610.c @@ -122,7 +122,7 @@ static int innovator1610_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver innovator1610_panel_driver = { +static struct platform_driver innovator1610_panel_driver = { .probe = innovator1610_panel_probe, .remove = innovator1610_panel_remove, .suspend = innovator1610_panel_suspend, @@ -133,16 +133,4 @@ struct platform_driver innovator1610_panel_driver = { }, }; -static int __init innovator1610_panel_drv_init(void) -{ - return platform_driver_register(&innovator1610_panel_driver); -} - -static void __exit innovator1610_panel_drv_cleanup(void) -{ - platform_driver_unregister(&innovator1610_panel_driver); -} - -module_init(innovator1610_panel_drv_init); -module_exit(innovator1610_panel_drv_cleanup); - +module_platform_driver(innovator1610_panel_driver); diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c index eb381db7fe51..8d546dd55e81 100644 --- a/drivers/video/omap/lcd_mipid.c +++ b/drivers/video/omap/lcd_mipid.c @@ -603,7 +603,6 @@ static int mipid_spi_remove(struct spi_device *spi) static struct spi_driver mipid_spi_driver = { .driver = { .name = MIPID_MODULE_NAME, - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = mipid_spi_probe, diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c index 6f8d13c41202..5914220dfa9c 100644 --- a/drivers/video/omap/lcd_osk.c +++ b/drivers/video/omap/lcd_osk.c @@ -116,7 +116,7 @@ static int osk_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver osk_panel_driver = { +static struct platform_driver osk_panel_driver = { .probe = osk_panel_probe, .remove = osk_panel_remove, .suspend = osk_panel_suspend, @@ -127,16 +127,4 @@ struct platform_driver osk_panel_driver = { }, }; -static int __init osk_panel_drv_init(void) -{ - return platform_driver_register(&osk_panel_driver); -} - -static void __exit osk_panel_drv_cleanup(void) -{ - platform_driver_unregister(&osk_panel_driver); -} - -module_init(osk_panel_drv_init); -module_exit(osk_panel_drv_cleanup); - +module_platform_driver(osk_panel_driver); diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c index 4cb301750d02..88c31eb0cd6c 100644 --- a/drivers/video/omap/lcd_palmte.c +++ b/drivers/video/omap/lcd_palmte.c @@ -97,7 +97,7 @@ static int palmte_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver palmte_panel_driver = { +static struct platform_driver palmte_panel_driver = { .probe = palmte_panel_probe, .remove = palmte_panel_remove, .suspend = palmte_panel_suspend, @@ -108,16 +108,4 @@ struct platform_driver palmte_panel_driver = { }, }; -static int __init palmte_panel_drv_init(void) -{ - return platform_driver_register(&palmte_panel_driver); -} - -static void __exit palmte_panel_drv_cleanup(void) -{ - platform_driver_unregister(&palmte_panel_driver); -} - -module_init(palmte_panel_drv_init); -module_exit(palmte_panel_drv_cleanup); - +module_platform_driver(palmte_panel_driver); diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c index b51b332e5a2b..aaf3c8ba1243 100644 --- a/drivers/video/omap/lcd_palmtt.c +++ b/drivers/video/omap/lcd_palmtt.c @@ -102,7 +102,7 @@ static int palmtt_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver palmtt_panel_driver = { +static struct platform_driver palmtt_panel_driver = { .probe = palmtt_panel_probe, .remove = palmtt_panel_remove, .suspend = palmtt_panel_suspend, @@ -113,15 +113,4 @@ struct platform_driver palmtt_panel_driver = { }, }; -static int __init palmtt_panel_drv_init(void) -{ - return platform_driver_register(&palmtt_panel_driver); -} - -static void __exit palmtt_panel_drv_cleanup(void) -{ - platform_driver_unregister(&palmtt_panel_driver); -} - -module_init(palmtt_panel_drv_init); -module_exit(palmtt_panel_drv_cleanup); +module_platform_driver(palmtt_panel_driver); diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c index 2334e56536bc..3b7d8aa1cf34 100644 --- a/drivers/video/omap/lcd_palmz71.c +++ b/drivers/video/omap/lcd_palmz71.c @@ -98,7 +98,7 @@ static int palmz71_panel_resume(struct platform_device *pdev) return 0; } -struct platform_driver palmz71_panel_driver = { +static struct platform_driver palmz71_panel_driver = { .probe = palmz71_panel_probe, .remove = palmz71_panel_remove, .suspend = palmz71_panel_suspend, @@ -109,15 +109,4 @@ struct platform_driver palmz71_panel_driver = { }, }; -static int __init palmz71_panel_drv_init(void) -{ - return platform_driver_register(&palmz71_panel_driver); -} - -static void __exit palmz71_panel_drv_cleanup(void) -{ - platform_driver_unregister(&palmz71_panel_driver); -} - -module_init(palmz71_panel_drv_init); -module_exit(palmz71_panel_drv_cleanup); +module_platform_driver(palmz71_panel_driver); diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index 25d8e5103193..b291bfaac80e 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -47,9 +47,9 @@ static unsigned int def_rotate; static unsigned int def_mirror; #ifdef CONFIG_FB_OMAP_MANUAL_UPDATE -static int manual_update = 1; +static bool manual_update = 1; #else -static int manual_update; +static bool manual_update; #endif static struct platform_device *fbdev_pdev; diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 8d8e1fe1901c..74d29b552901 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -41,7 +41,7 @@ config PANEL_NEC_NL8048HL11_01B config PANEL_PICODLP tristate "TI PICO DLP mini-projector" - depends on OMAP2_DSS && I2C + depends on OMAP2_DSS_DPI && I2C help A mini-projector used in TI's SDP4430 and EVM boards For more info please visit http://www.dlp.com/projector/ diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index dbd59b8e5b36..51a87e149e24 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -803,7 +803,6 @@ static int acx565akm_spi_remove(struct spi_device *spi) static struct spi_driver acx565akm_spi_driver = { .driver = { .name = "acx565akm", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = acx565akm_spi_probe, diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 519c47d2057f..28b9a6d61b0f 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -297,6 +297,72 @@ static struct panel_config generic_dpi_panels[] = { .name = "apollon", }, + /* FocalTech ETM070003DH6 */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 28000, + + .hsw = 48, + .hfp = 40, + .hbp = 40, + + .vsw = 3, + .vfp = 13, + .vbp = 29, + }, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .name = "focaltech_etm070003dh6", + }, + + /* Microtips Technologies - UMSH-8173MD */ + { + { + .x_res = 800, + .y_res = 480, + + .pixel_clock = 34560, + + .hsw = 13, + .hfp = 101, + .hbp = 101, + + .vsw = 23, + .vfp = 1, + .vbp = 1, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "microtips_umsh_8173md", + }, + + /* OrtusTech COM43H4M10XTC */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 8000, + + .hsw = 41, + .hfp = 8, + .hbp = 4, + + .vsw = 10, + .vfp = 4, + .vbp = 2, + }, + .config = OMAP_DSS_LCD_TFT, + + .name = "ortustech_com43h4m10xtc", + }, }; struct panel_drv_data { diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 150e8bae35a1..dc9408dc93d1 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -708,7 +708,6 @@ static int mipid_spi_remove(struct spi_device *spi) static struct spi_driver mipid_spi_driver = { .driver = { .name = "lcd_mipid", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = mipid_spi_probe, diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 2ba9d0ca187c..0eb31caddca8 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -163,50 +163,93 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev) kfree(necd); } -static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) { - int r = 0; + int r; struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); struct backlight_device *bl = necd->bl; + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + if (dssdev->platform_enable) { r = dssdev->platform_enable(dssdev); if (r) - return r; + goto err1; } r = nec_8048_bl_update_status(bl); if (r < 0) dev_err(&dssdev->dev, "failed to set lcd brightness\n"); - r = omapdss_dpi_display_enable(dssdev); - + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: return r; } -static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) { struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); struct backlight_device *bl = necd->bl; - omapdss_dpi_display_disable(dssdev); + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; bl->props.brightness = 0; nec_8048_bl_update_status(bl); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); + + omapdss_dpi_display_disable(dssdev); +} + +static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + r = nec_8048_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void nec_8048_panel_disable(struct omap_dss_device *dssdev) +{ + nec_8048_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) { - nec_8048_panel_disable(dssdev); + nec_8048_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + return 0; } static int nec_8048_panel_resume(struct omap_dss_device *dssdev) { - return nec_8048_panel_enable(dssdev); + int r; + + r = nec_8048_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; } static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) @@ -303,7 +346,6 @@ static struct spi_driver nec_8048_spi_driver = { .resume = nec_8048_spi_resume, .driver = { .name = "nec_8048_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, }; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 80c3f6ab1a94..00c5c615585f 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -198,12 +198,6 @@ struct taal_data { bool te_enabled; atomic_t do_update; - struct { - u16 x; - u16 y; - u16 w; - u16 h; - } update_region; int channel; struct delayed_work te_timeout_work; @@ -1188,6 +1182,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; + r = dsi_enable_video_output(dssdev, td->channel); + if (r) + goto err; + td->enabled = 1; if (!td->intro_printed) { @@ -1217,6 +1215,8 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; + dsi_disable_video_output(dssdev, td->channel); + r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); if (!r) r = taal_sleep_in(td); @@ -1394,12 +1394,8 @@ static irqreturn_t taal_te_isr(int irq, void *data) if (old) { cancel_delayed_work(&td->te_timeout_work); - r = omap_dsi_update(dssdev, td->channel, - td->update_region.x, - td->update_region.y, - td->update_region.w, - td->update_region.h, - taal_framedone_cb, dssdev); + r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, + dssdev); if (r) goto err; } @@ -1444,26 +1440,20 @@ static int taal_update(struct omap_dss_device *dssdev, goto err; } - r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); - if (r) - goto err; - - r = taal_set_update_window(td, x, y, w, h); + /* XXX no need to send this every frame, but dsi break if not done */ + r = taal_set_update_window(td, 0, 0, + td->panel_config->timings.x_res, + td->panel_config->timings.y_res); if (r) goto err; if (td->te_enabled && panel_data->use_ext_te) { - td->update_region.x = x; - td->update_region.y = y; - td->update_region.w = w; - td->update_region.h = h; - barrier(); schedule_delayed_work(&td->te_timeout_work, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); } else { - r = omap_dsi_update(dssdev, td->channel, x, y, w, h, - taal_framedone_cb, dssdev); + r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, + dssdev); if (r) goto err; } diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 2462b9ec6662..e6649aa89591 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -512,7 +512,6 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi) static struct spi_driver tpo_td043_spi_driver = { .driver = { .name = "tpo_td043mtea1_panel_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = tpo_td043_spi_probe, diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index bd34ac5b2026..5c450b0f94d0 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o -omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o +omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ + manager.o overlay.o apply.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c new file mode 100644 index 000000000000..052dc874cd3d --- /dev/null +++ b/drivers/video/omap2/dss/apply.c @@ -0,0 +1,1324 @@ +/* + * Copyright (C) 2011 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "APPLY" + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/jiffies.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +/* + * We have 4 levels of cache for the dispc settings. First two are in SW and + * the latter two in HW. + * + * set_info() + * v + * +--------------------+ + * | user_info | + * +--------------------+ + * v + * apply() + * v + * +--------------------+ + * | info | + * +--------------------+ + * v + * write_regs() + * v + * +--------------------+ + * | shadow registers | + * +--------------------+ + * v + * VFP or lcd/digit_enable + * v + * +--------------------+ + * | registers | + * +--------------------+ + */ + +struct ovl_priv_data { + + bool user_info_dirty; + struct omap_overlay_info user_info; + + bool info_dirty; + struct omap_overlay_info info; + + bool shadow_info_dirty; + + bool extra_info_dirty; + bool shadow_extra_info_dirty; + + bool enabled; + enum omap_channel channel; + u32 fifo_low, fifo_high; + + /* + * True if overlay is to be enabled. Used to check and calculate configs + * for the overlay before it is enabled in the HW. + */ + bool enabling; +}; + +struct mgr_priv_data { + + bool user_info_dirty; + struct omap_overlay_manager_info user_info; + + bool info_dirty; + struct omap_overlay_manager_info info; + + bool shadow_info_dirty; + + /* If true, GO bit is up and shadow registers cannot be written. + * Never true for manual update displays */ + bool busy; + + /* If true, dispc output is enabled */ + bool updating; + + /* If true, a display is enabled using this manager */ + bool enabled; +}; + +static struct { + struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; + struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; + + bool irq_enabled; +} dss_data; + +/* protects dss_data */ +static spinlock_t data_lock; +/* lock for blocking functions */ +static DEFINE_MUTEX(apply_lock); +static DECLARE_COMPLETION(extra_updated_completion); + +static void dss_register_vsync_isr(void); + +static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) +{ + return &dss_data.ovl_priv_data_array[ovl->id]; +} + +static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) +{ + return &dss_data.mgr_priv_data_array[mgr->id]; +} + +void dss_apply_init(void) +{ + const int num_ovls = dss_feat_get_num_ovls(); + int i; + + spin_lock_init(&data_lock); + + for (i = 0; i < num_ovls; ++i) { + struct ovl_priv_data *op; + + op = &dss_data.ovl_priv_data_array[i]; + + op->info.global_alpha = 255; + + switch (i) { + case 0: + op->info.zorder = 0; + break; + case 1: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; + break; + case 2: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; + break; + case 3: + op->info.zorder = + dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; + break; + } + + op->user_info = op->info; + } +} + +static bool ovl_manual_update(struct omap_overlay *ovl) +{ + return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +} + +static bool mgr_manual_update(struct omap_overlay_manager *mgr) +{ + return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; +} + +static int dss_check_settings_low(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, bool applying) +{ + struct omap_overlay_info *oi; + struct omap_overlay_manager_info *mi; + struct omap_overlay *ovl; + struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; + struct ovl_priv_data *op; + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (applying && mp->user_info_dirty) + mi = &mp->user_info; + else + mi = &mp->info; + + /* collect the infos to be tested into the array */ + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + + if (!op->enabled && !op->enabling) + oi = NULL; + else if (applying && op->user_info_dirty) + oi = &op->user_info; + else + oi = &op->info; + + ois[ovl->id] = oi; + } + + return dss_mgr_check(mgr, dssdev, mi, ois); +} + +/* + * check manager and overlay settings using overlay_info from data->info + */ +static int dss_check_settings(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + return dss_check_settings_low(mgr, dssdev, false); +} + +/* + * check manager and overlay settings using overlay_info from ovl->info if + * dirty and from data->info otherwise + */ +static int dss_check_settings_apply(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + return dss_check_settings_low(mgr, dssdev, true); +} + +static bool need_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + struct omap_overlay *ovl; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + continue; + + if (mgr_manual_update(mgr)) { + /* to catch FRAMEDONE */ + if (mp->updating) + return true; + } else { + /* to catch GO bit going down */ + if (mp->busy) + return true; + + /* to write new values to registers */ + if (mp->info_dirty) + return true; + + /* to set GO bit */ + if (mp->shadow_info_dirty) + return true; + + list_for_each_entry(ovl, &mgr->overlays, list) { + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + /* + * NOTE: we check extra_info flags even for + * disabled overlays, as extra_infos need to be + * always written. + */ + + /* to write new values to registers */ + if (op->extra_info_dirty) + return true; + + /* to set GO bit */ + if (op->shadow_extra_info_dirty) + return true; + + if (!op->enabled) + continue; + + /* to write new values to registers */ + if (op->info_dirty) + return true; + + /* to set GO bit */ + if (op->shadow_info_dirty) + return true; + } + } + } + + return false; +} + +static bool need_go(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + struct ovl_priv_data *op; + + mp = get_mgr_priv(mgr); + + if (mp->shadow_info_dirty) + return true; + + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + if (op->shadow_info_dirty || op->shadow_extra_info_dirty) + return true; + } + + return false; +} + +/* returns true if an extra_info field is currently being updated */ +static bool extra_info_update_ongoing(void) +{ + const int num_ovls = omap_dss_get_num_overlays(); + struct ovl_priv_data *op; + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + int i; + + for (i = 0; i < num_ovls; ++i) { + ovl = omap_dss_get_overlay(i); + op = get_ovl_priv(ovl); + + if (!ovl->manager) + continue; + + mp = get_mgr_priv(ovl->manager); + + if (!mp->enabled) + continue; + + if (!mp->updating) + continue; + + if (op->extra_info_dirty || op->shadow_extra_info_dirty) + return true; + } + + return false; +} + +/* wait until no extra_info updates are pending */ +static void wait_pending_extra_info_updates(void) +{ + bool updating; + unsigned long flags; + unsigned long t; + + spin_lock_irqsave(&data_lock, flags); + + updating = extra_info_update_ongoing(); + + if (!updating) { + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + init_completion(&extra_updated_completion); + + spin_unlock_irqrestore(&data_lock, flags); + + t = msecs_to_jiffies(500); + wait_for_completion_timeout(&extra_updated_completion, t); + + updating = extra_info_update_ongoing(); + + WARN_ON(updating); +} + +int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) +{ + unsigned long timeout = msecs_to_jiffies(500); + struct mgr_priv_data *mp; + u32 irq; + int r; + int i; + struct omap_dss_device *dssdev = mgr->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + if (mgr_manual_update(mgr)) + return 0; + + irq = dispc_mgr_get_vsync_irq(mgr->id); + + mp = get_mgr_priv(mgr); + i = 0; + while (1) { + unsigned long flags; + bool shadow_dirty, dirty; + + spin_lock_irqsave(&data_lock, flags); + dirty = mp->info_dirty; + shadow_dirty = mp->shadow_info_dirty; + spin_unlock_irqrestore(&data_lock, flags); + + if (!dirty && !shadow_dirty) { + r = 0; + break; + } + + /* 4 iterations is the worst case: + * 1 - initial iteration, dirty = true (between VFP and VSYNC) + * 2 - first VSYNC, dirty = true + * 3 - dirty = false, shadow_dirty = true + * 4 - shadow_dirty = false */ + if (i++ == 3) { + DSSERR("mgr(%d)->wait_for_go() not finishing\n", + mgr->id); + r = 0; + break; + } + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + if (r == -ERESTARTSYS) + break; + + if (r) { + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); + break; + } + } + + return r; +} + +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) +{ + unsigned long timeout = msecs_to_jiffies(500); + struct ovl_priv_data *op; + struct omap_dss_device *dssdev; + u32 irq; + int r; + int i; + + if (!ovl->manager) + return 0; + + dssdev = ovl->manager->device; + + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + if (ovl_manual_update(ovl)) + return 0; + + irq = dispc_mgr_get_vsync_irq(ovl->manager->id); + + op = get_ovl_priv(ovl); + i = 0; + while (1) { + unsigned long flags; + bool shadow_dirty, dirty; + + spin_lock_irqsave(&data_lock, flags); + dirty = op->info_dirty; + shadow_dirty = op->shadow_info_dirty; + spin_unlock_irqrestore(&data_lock, flags); + + if (!dirty && !shadow_dirty) { + r = 0; + break; + } + + /* 4 iterations is the worst case: + * 1 - initial iteration, dirty = true (between VFP and VSYNC) + * 2 - first VSYNC, dirty = true + * 3 - dirty = false, shadow_dirty = true + * 4 - shadow_dirty = false */ + if (i++ == 3) { + DSSERR("ovl(%d)->wait_for_go() not finishing\n", + ovl->id); + r = 0; + break; + } + + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); + if (r == -ERESTARTSYS) + break; + + if (r) { + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); + break; + } + } + + return r; +} + +static void dss_ovl_write_regs(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct omap_overlay_info *oi; + bool ilace, replication; + struct mgr_priv_data *mp; + int r; + + DSSDBGF("%d", ovl->id); + + if (!op->enabled || !op->info_dirty) + return; + + oi = &op->info; + + replication = dss_use_replication(ovl->manager->device, oi->color_mode); + + ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; + + r = dispc_ovl_setup(ovl->id, oi, ilace, replication); + if (r) { + /* + * We can't do much here, as this function can be called from + * vsync interrupt. + */ + DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); + + /* This will leave fifo configurations in a nonoptimal state */ + op->enabled = false; + dispc_ovl_enable(ovl->id, false); + return; + } + + mp = get_mgr_priv(ovl->manager); + + op->info_dirty = false; + if (mp->updating) + op->shadow_info_dirty = true; +} + +static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct mgr_priv_data *mp; + + DSSDBGF("%d", ovl->id); + + if (!op->extra_info_dirty) + return; + + /* note: write also when op->enabled == false, so that the ovl gets + * disabled */ + + dispc_ovl_enable(ovl->id, op->enabled); + dispc_ovl_set_channel_out(ovl->id, op->channel); + dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); + + mp = get_mgr_priv(ovl->manager); + + op->extra_info_dirty = false; + if (mp->updating) + op->shadow_extra_info_dirty = true; +} + +static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + struct omap_overlay *ovl; + + DSSDBGF("%d", mgr->id); + + if (!mp->enabled) + return; + + WARN_ON(mp->busy); + + /* Commit overlay settings */ + list_for_each_entry(ovl, &mgr->overlays, list) { + dss_ovl_write_regs(ovl); + dss_ovl_write_regs_extra(ovl); + } + + if (mp->info_dirty) { + dispc_mgr_setup(mgr->id, &mp->info); + + mp->info_dirty = false; + if (mp->updating) + mp->shadow_info_dirty = true; + } +} + +static void dss_write_regs(void) +{ + const int num_mgrs = omap_dss_get_num_overlay_managers(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + int r; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) + continue; + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("cannot write registers for manager %s: " + "illegal configuration\n", mgr->name); + continue; + } + + dss_mgr_write_regs(mgr); + } +} + +static void dss_set_go_bits(void) +{ + const int num_mgrs = omap_dss_get_num_overlay_managers(); + int i; + + for (i = 0; i < num_mgrs; ++i) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) + continue; + + if (!need_go(mgr)) + continue; + + mp->busy = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_mgr_go(mgr->id); + } + +} + +void dss_mgr_start_update(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + spin_lock_irqsave(&data_lock, flags); + + WARN_ON(mp->updating); + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("cannot start manual update: illegal configuration\n"); + spin_unlock_irqrestore(&data_lock, flags); + return; + } + + dss_mgr_write_regs(mgr); + + mp->updating = true; + + if (!dss_data.irq_enabled && need_isr()) + dss_register_vsync_isr(); + + dispc_mgr_enable(mgr->id, true); + + spin_unlock_irqrestore(&data_lock, flags); +} + +static void dss_apply_irq_handler(void *data, u32 mask); + +static void dss_register_vsync_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + u32 mask; + int r, i; + + mask = 0; + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_vsync_irq(i); + + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_framedone_irq(i); + + r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); + WARN_ON(r); + + dss_data.irq_enabled = true; +} + +static void dss_unregister_vsync_isr(void) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + u32 mask; + int r, i; + + mask = 0; + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_vsync_irq(i); + + for (i = 0; i < num_mgrs; ++i) + mask |= dispc_mgr_get_framedone_irq(i); + + r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); + WARN_ON(r); + + dss_data.irq_enabled = false; +} + +static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + struct ovl_priv_data *op; + + mp = get_mgr_priv(mgr); + mp->shadow_info_dirty = false; + + list_for_each_entry(ovl, &mgr->overlays, list) { + op = get_ovl_priv(ovl); + op->shadow_info_dirty = false; + op->shadow_extra_info_dirty = false; + } +} + +static void dss_apply_irq_handler(void *data, u32 mask) +{ + const int num_mgrs = dss_feat_get_num_mgrs(); + int i; + bool extra_updating; + + spin_lock(&data_lock); + + /* clear busy, updating flags, shadow_dirty flags */ + for (i = 0; i < num_mgrs; i++) { + struct omap_overlay_manager *mgr; + struct mgr_priv_data *mp; + bool was_updating; + + mgr = omap_dss_get_overlay_manager(i); + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + continue; + + was_updating = mp->updating; + mp->updating = dispc_mgr_is_enabled(i); + + if (!mgr_manual_update(mgr)) { + bool was_busy = mp->busy; + mp->busy = dispc_mgr_go_busy(i); + + if (was_busy && !mp->busy) + mgr_clear_shadow_dirty(mgr); + } else { + if (was_updating && !mp->updating) + mgr_clear_shadow_dirty(mgr); + } + } + + dss_write_regs(); + dss_set_go_bits(); + + extra_updating = extra_info_update_ongoing(); + if (!extra_updating) + complete_all(&extra_updated_completion); + + if (!need_isr()) + dss_unregister_vsync_isr(); + + spin_unlock(&data_lock); +} + +static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + if (!op->user_info_dirty) + return; + + op->user_info_dirty = false; + op->info_dirty = true; + op->info = op->user_info; +} + +static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (!mp->user_info_dirty) + return; + + mp->user_info_dirty = false; + mp->info_dirty = true; + mp->info = mp->user_info; +} + +int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) +{ + unsigned long flags; + struct omap_overlay *ovl; + int r; + + DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); + + spin_lock_irqsave(&data_lock, flags); + + r = dss_check_settings_apply(mgr, mgr->device); + if (r) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("failed to apply settings: illegal configuration.\n"); + return r; + } + + /* Configure overlays */ + list_for_each_entry(ovl, &mgr->overlays, list) + omap_dss_mgr_apply_ovl(ovl); + + /* Configure manager */ + omap_dss_mgr_apply_mgr(mgr); + + dss_write_regs(); + dss_set_go_bits(); + + spin_unlock_irqrestore(&data_lock, flags); + + return 0; +} + +static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) +{ + struct ovl_priv_data *op; + + op = get_ovl_priv(ovl); + + if (op->enabled == enable) + return; + + op->enabled = enable; + op->extra_info_dirty = true; +} + +static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, + u32 fifo_low, u32 fifo_high) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + + if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) + return; + + op->fifo_low = fifo_low; + op->fifo_high = fifo_high; + op->extra_info_dirty = true; +} + +static void dss_ovl_setup_fifo(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + struct omap_dss_device *dssdev; + u32 size, burst_size; + u32 fifo_low, fifo_high; + + if (!op->enabled && !op->enabling) + return; + + dssdev = ovl->manager->device; + + size = dispc_ovl_get_fifo_size(ovl->id); + + burst_size = dispc_ovl_get_burst_size(ovl->id); + + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_DPI: + case OMAP_DISPLAY_TYPE_DBI: + case OMAP_DISPLAY_TYPE_SDI: + case OMAP_DISPLAY_TYPE_VENC: + case OMAP_DISPLAY_TYPE_HDMI: + default_get_overlay_fifo_thresholds(ovl->id, size, + burst_size, &fifo_low, &fifo_high); + break; +#ifdef CONFIG_OMAP2_DSS_DSI + case OMAP_DISPLAY_TYPE_DSI: + dsi_get_overlay_fifo_thresholds(ovl->id, size, + burst_size, &fifo_low, &fifo_high); + break; +#endif + default: + BUG(); + } + + dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); +} + +static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) +{ + struct omap_overlay *ovl; + struct mgr_priv_data *mp; + + mp = get_mgr_priv(mgr); + + if (!mp->enabled) + return; + + list_for_each_entry(ovl, &mgr->overlays, list) + dss_ovl_setup_fifo(ovl); +} + +static void dss_setup_fifos(void) +{ + const int num_mgrs = omap_dss_get_num_overlay_managers(); + struct omap_overlay_manager *mgr; + int i; + + for (i = 0; i < num_mgrs; ++i) { + mgr = omap_dss_get_overlay_manager(i); + dss_mgr_setup_fifos(mgr); + } +} + +int dss_mgr_enable(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (mp->enabled) + goto out; + + spin_lock_irqsave(&data_lock, flags); + + mp->enabled = true; + + r = dss_check_settings(mgr, mgr->device); + if (r) { + DSSERR("failed to enable manager %d: check_settings failed\n", + mgr->id); + goto err; + } + + dss_setup_fifos(); + + dss_write_regs(); + dss_set_go_bits(); + + if (!mgr_manual_update(mgr)) + mp->updating = true; + + spin_unlock_irqrestore(&data_lock, flags); + + if (!mgr_manual_update(mgr)) + dispc_mgr_enable(mgr->id, true); + +out: + mutex_unlock(&apply_lock); + + return 0; + +err: + mp->enabled = false; + spin_unlock_irqrestore(&data_lock, flags); + mutex_unlock(&apply_lock); + return r; +} + +void dss_mgr_disable(struct omap_overlay_manager *mgr) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + + mutex_lock(&apply_lock); + + if (!mp->enabled) + goto out; + + if (!mgr_manual_update(mgr)) + dispc_mgr_enable(mgr->id, false); + + spin_lock_irqsave(&data_lock, flags); + + mp->updating = false; + mp->enabled = false; + + spin_unlock_irqrestore(&data_lock, flags); + +out: + mutex_unlock(&apply_lock); +} + +int dss_mgr_set_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + int r; + + r = dss_mgr_simple_check(mgr, info); + if (r) + return r; + + spin_lock_irqsave(&data_lock, flags); + + mp->user_info = *info; + mp->user_info_dirty = true; + + spin_unlock_irqrestore(&data_lock, flags); + + return 0; +} + +void dss_mgr_get_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info) +{ + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; + + spin_lock_irqsave(&data_lock, flags); + + *info = mp->user_info; + + spin_unlock_irqrestore(&data_lock, flags); +} + +int dss_mgr_set_device(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&apply_lock); + + if (dssdev->manager) { + DSSERR("display '%s' already has a manager '%s'\n", + dssdev->name, dssdev->manager->name); + r = -EINVAL; + goto err; + } + + if ((mgr->supported_displays & dssdev->type) == 0) { + DSSERR("display '%s' does not support manager '%s'\n", + dssdev->name, mgr->name); + r = -EINVAL; + goto err; + } + + dssdev->manager = mgr; + mgr->device = dssdev; + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + +int dss_mgr_unset_device(struct omap_overlay_manager *mgr) +{ + int r; + + mutex_lock(&apply_lock); + + if (!mgr->device) { + DSSERR("failed to unset display, display not set.\n"); + r = -EINVAL; + goto err; + } + + /* + * Don't allow currently enabled displays to have the overlay manager + * pulled out from underneath them + */ + if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } + + mgr->device->manager = NULL; + mgr->device = NULL; + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + + +int dss_ovl_set_info(struct omap_overlay *ovl, + struct omap_overlay_info *info) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + r = dss_ovl_simple_check(ovl, info); + if (r) + return r; + + spin_lock_irqsave(&data_lock, flags); + + op->user_info = *info; + op->user_info_dirty = true; + + spin_unlock_irqrestore(&data_lock, flags); + + return 0; +} + +void dss_ovl_get_info(struct omap_overlay *ovl, + struct omap_overlay_info *info) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + + spin_lock_irqsave(&data_lock, flags); + + *info = op->user_info; + + spin_unlock_irqrestore(&data_lock, flags); +} + +int dss_ovl_set_manager(struct omap_overlay *ovl, + struct omap_overlay_manager *mgr) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + if (!mgr) + return -EINVAL; + + mutex_lock(&apply_lock); + + if (ovl->manager) { + DSSERR("overlay '%s' already has a manager '%s'\n", + ovl->name, ovl->manager->name); + r = -EINVAL; + goto err; + } + + spin_lock_irqsave(&data_lock, flags); + + if (op->enabled) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("overlay has to be disabled to change the manager\n"); + r = -EINVAL; + goto err; + } + + op->channel = mgr->id; + op->extra_info_dirty = true; + + ovl->manager = mgr; + list_add_tail(&ovl->list, &mgr->overlays); + + spin_unlock_irqrestore(&data_lock, flags); + + /* XXX: When there is an overlay on a DSI manual update display, and + * the overlay is first disabled, then moved to tv, and enabled, we + * seem to get SYNC_LOST_DIGIT error. + * + * Waiting doesn't seem to help, but updating the manual update display + * after disabling the overlay seems to fix this. This hints that the + * overlay is perhaps somehow tied to the LCD output until the output + * is updated. + * + * Userspace workaround for this is to update the LCD after disabling + * the overlay, but before moving the overlay to TV. + */ + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + +int dss_ovl_unset_manager(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (!ovl->manager) { + DSSERR("failed to detach overlay: manager not set\n"); + r = -EINVAL; + goto err; + } + + spin_lock_irqsave(&data_lock, flags); + + if (op->enabled) { + spin_unlock_irqrestore(&data_lock, flags); + DSSERR("overlay has to be disabled to unset the manager\n"); + r = -EINVAL; + goto err; + } + + op->channel = -1; + + ovl->manager = NULL; + list_del(&ovl->list); + + spin_unlock_irqrestore(&data_lock, flags); + + mutex_unlock(&apply_lock); + + return 0; +err: + mutex_unlock(&apply_lock); + return r; +} + +bool dss_ovl_is_enabled(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + bool e; + + spin_lock_irqsave(&data_lock, flags); + + e = op->enabled; + + spin_unlock_irqrestore(&data_lock, flags); + + return e; +} + +int dss_ovl_enable(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (op->enabled) { + r = 0; + goto err1; + } + + if (ovl->manager == NULL || ovl->manager->device == NULL) { + r = -EINVAL; + goto err1; + } + + spin_lock_irqsave(&data_lock, flags); + + op->enabling = true; + + r = dss_check_settings(ovl->manager, ovl->manager->device); + if (r) { + DSSERR("failed to enable overlay %d: check_settings failed\n", + ovl->id); + goto err2; + } + + dss_setup_fifos(); + + op->enabling = false; + dss_apply_ovl_enable(ovl, true); + + dss_write_regs(); + dss_set_go_bits(); + + spin_unlock_irqrestore(&data_lock, flags); + + mutex_unlock(&apply_lock); + + return 0; +err2: + op->enabling = false; + spin_unlock_irqrestore(&data_lock, flags); +err1: + mutex_unlock(&apply_lock); + return r; +} + +int dss_ovl_disable(struct omap_overlay *ovl) +{ + struct ovl_priv_data *op = get_ovl_priv(ovl); + unsigned long flags; + int r; + + mutex_lock(&apply_lock); + + if (!op->enabled) { + r = 0; + goto err; + } + + if (ovl->manager == NULL || ovl->manager->device == NULL) { + r = -EINVAL; + goto err; + } + + spin_lock_irqsave(&data_lock, flags); + + dss_apply_ovl_enable(ovl, false); + dss_write_regs(); + dss_set_go_bits(); + + spin_unlock_irqrestore(&data_lock, flags); + + mutex_unlock(&apply_lock); + + return 0; + +err: + mutex_unlock(&apply_lock); + return r; +} + diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 86ec12e16c7c..8613f86fb56d 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -50,7 +50,7 @@ module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp, "default display name"); #ifdef DEBUG -unsigned int dss_debug; +bool dss_debug; module_param_named(debug, dss_debug, bool, 0644); #endif @@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev) dss_features_init(); + dss_apply_init(); + dss_init_overlay_managers(pdev); dss_init_overlays(pdev); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5c81533eacaa..a5ec7f37c185 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -64,22 +64,6 @@ struct omap_dispc_isr_data { u32 mask; }; -struct dispc_h_coef { - s8 hc4; - s8 hc3; - u8 hc2; - s8 hc1; - s8 hc0; -}; - -struct dispc_v_coef { - s8 vc22; - s8 vc2; - u8 vc1; - s8 vc0; - s8 vc00; -}; - enum omap_burst_size { BURST_SIZE_X2 = 0, BURST_SIZE_X4 = 1, @@ -438,6 +422,34 @@ static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel) return mgr ? mgr->device : NULL; } +u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) +{ + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return DISPC_IRQ_VSYNC; + case OMAP_DSS_CHANNEL_LCD2: + return DISPC_IRQ_VSYNC2; + case OMAP_DSS_CHANNEL_DIGIT: + return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; + default: + BUG(); + } +} + +u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) +{ + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return DISPC_IRQ_FRAMEDONE; + case OMAP_DSS_CHANNEL_LCD2: + return DISPC_IRQ_FRAMEDONE2; + case OMAP_DSS_CHANNEL_DIGIT: + return 0; + default: + BUG(); + } +} + bool dispc_mgr_go_busy(enum omap_channel channel) { int bit; @@ -533,105 +545,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); } -static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, - int vscaleup, int five_taps, - enum omap_color_component color_comp) -{ - /* Coefficients for horizontal up-sampling */ - static const struct dispc_h_coef coef_hup[8] = { - { 0, 0, 128, 0, 0 }, - { -1, 13, 124, -8, 0 }, - { -2, 30, 112, -11, -1 }, - { -5, 51, 95, -11, -2 }, - { 0, -9, 73, 73, -9 }, - { -2, -11, 95, 51, -5 }, - { -1, -11, 112, 30, -2 }, - { 0, -8, 124, 13, -1 }, - }; - - /* Coefficients for vertical up-sampling */ - static const struct dispc_v_coef coef_vup_3tap[8] = { - { 0, 0, 128, 0, 0 }, - { 0, 3, 123, 2, 0 }, - { 0, 12, 111, 5, 0 }, - { 0, 32, 89, 7, 0 }, - { 0, 0, 64, 64, 0 }, - { 0, 7, 89, 32, 0 }, - { 0, 5, 111, 12, 0 }, - { 0, 2, 123, 3, 0 }, - }; - - static const struct dispc_v_coef coef_vup_5tap[8] = { - { 0, 0, 128, 0, 0 }, - { -1, 13, 124, -8, 0 }, - { -2, 30, 112, -11, -1 }, - { -5, 51, 95, -11, -2 }, - { 0, -9, 73, 73, -9 }, - { -2, -11, 95, 51, -5 }, - { -1, -11, 112, 30, -2 }, - { 0, -8, 124, 13, -1 }, - }; - - /* Coefficients for horizontal down-sampling */ - static const struct dispc_h_coef coef_hdown[8] = { - { 0, 36, 56, 36, 0 }, - { 4, 40, 55, 31, -2 }, - { 8, 44, 54, 27, -5 }, - { 12, 48, 53, 22, -7 }, - { -9, 17, 52, 51, 17 }, - { -7, 22, 53, 48, 12 }, - { -5, 27, 54, 44, 8 }, - { -2, 31, 55, 40, 4 }, - }; - - /* Coefficients for vertical down-sampling */ - static const struct dispc_v_coef coef_vdown_3tap[8] = { - { 0, 36, 56, 36, 0 }, - { 0, 40, 57, 31, 0 }, - { 0, 45, 56, 27, 0 }, - { 0, 50, 55, 23, 0 }, - { 0, 18, 55, 55, 0 }, - { 0, 23, 55, 50, 0 }, - { 0, 27, 56, 45, 0 }, - { 0, 31, 57, 40, 0 }, - }; - - static const struct dispc_v_coef coef_vdown_5tap[8] = { - { 0, 36, 56, 36, 0 }, - { 4, 40, 55, 31, -2 }, - { 8, 44, 54, 27, -5 }, - { 12, 48, 53, 22, -7 }, - { -9, 17, 52, 51, 17 }, - { -7, 22, 53, 48, 12 }, - { -5, 27, 54, 44, 8 }, - { -2, 31, 55, 40, 4 }, - }; - - const struct dispc_h_coef *h_coef; - const struct dispc_v_coef *v_coef; +static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, + int fir_vinc, int five_taps, + enum omap_color_component color_comp) +{ + const struct dispc_coef *h_coef, *v_coef; int i; - if (hscaleup) - h_coef = coef_hup; - else - h_coef = coef_hdown; - - if (vscaleup) - v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; - else - v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; + h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); + v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); for (i = 0; i < 8; i++) { u32 h, hv; - h = FLD_VAL(h_coef[i].hc0, 7, 0) - | FLD_VAL(h_coef[i].hc1, 15, 8) - | FLD_VAL(h_coef[i].hc2, 23, 16) - | FLD_VAL(h_coef[i].hc3, 31, 24); - hv = FLD_VAL(h_coef[i].hc4, 7, 0) - | FLD_VAL(v_coef[i].vc0, 15, 8) - | FLD_VAL(v_coef[i].vc1, 23, 16) - | FLD_VAL(v_coef[i].vc2, 31, 24); + h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) + | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) + | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) + | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); + hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) + | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) + | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) + | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { dispc_ovl_write_firh_reg(plane, i, h); @@ -646,8 +580,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, if (five_taps) { for (i = 0; i < 8; i++) { u32 v; - v = FLD_VAL(v_coef[i].vc00, 7, 0) - | FLD_VAL(v_coef[i].vc22, 15, 8); + v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) + | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) dispc_ovl_write_firv_reg(plane, i, v); else @@ -875,8 +809,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); } -static void dispc_ovl_set_channel_out(enum omap_plane plane, - enum omap_channel channel) +void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) { int shift; u32 val; @@ -923,6 +856,39 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane, dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } +static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) +{ + int shift; + u32 val; + enum omap_channel channel; + + switch (plane) { + case OMAP_DSS_GFX: + shift = 8; + break; + case OMAP_DSS_VIDEO1: + case OMAP_DSS_VIDEO2: + case OMAP_DSS_VIDEO3: + shift = 16; + break; + default: + BUG(); + } + + val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + + if (dss_has_feature(FEAT_MGR_LCD2)) { + if (FLD_GET(val, 31, 30) == 0) + channel = FLD_GET(val, shift, shift); + else + channel = OMAP_DSS_CHANNEL_LCD2; + } else { + channel = FLD_GET(val, shift, shift); + } + + return channel; +} + static void dispc_ovl_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { @@ -964,7 +930,7 @@ void dispc_enable_gamma_table(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); } -void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) +static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) { u16 reg; @@ -978,7 +944,7 @@ void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) REG_FLD_MOD(reg, enable, 15, 15); } -void dispc_mgr_set_cpr_coef(enum omap_channel channel, +static void dispc_mgr_set_cpr_coef(enum omap_channel channel, struct omap_dss_cpr_coefs *coefs) { u32 coef_r, coef_g, coef_b; @@ -1057,8 +1023,7 @@ u32 dispc_ovl_get_fifo_size(enum omap_plane plane) return dispc.fifo_size[plane]; } -static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, - u32 high) +void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) { u8 hi_start, hi_end, lo_start, lo_end; u32 unit; @@ -1169,17 +1134,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane, enum omap_color_component color_comp) { int fir_hinc, fir_vinc; - int hscaleup, vscaleup; - - hscaleup = orig_width <= out_width; - vscaleup = orig_height <= out_height; - - dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps, - color_comp); fir_hinc = 1024 * orig_width / out_width; fir_vinc = 1024 * orig_height / out_height; + dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, + color_comp); dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); } @@ -1654,6 +1614,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, u32 fclk = 0; u64 tmp, pclk = dispc_mgr_pclk_rate(channel); + if (height <= out_height && width <= out_width) + return (unsigned long) pclk; + if (height > out_height) { struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); unsigned int ppl = dssdev->panel.timings.x_res; @@ -1708,7 +1671,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, else vf = 1; - return dispc_mgr_pclk_rate(channel) * vf * hf; + if (cpu_is_omap24xx()) { + if (vf > 1 && hf > 1) + return dispc_mgr_pclk_rate(channel) * 4; + else + return dispc_mgr_pclk_rate(channel) * 2; + } else if (cpu_is_omap34xx()) { + return dispc_mgr_pclk_rate(channel) * vf * hf; + } else { + return dispc_mgr_pclk_rate(channel) * hf; + } } static int dispc_ovl_calc_scaling(enum omap_plane plane, @@ -1718,6 +1690,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, { struct omap_overlay *ovl = omap_dss_get_overlay(plane); const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); unsigned long fclk = 0; if (width == out_width && height == out_height) @@ -1734,28 +1708,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, out_height > height * 8) return -EINVAL; - /* Must use 5-tap filter? */ - *five_taps = height > out_height * 2; - - if (!*five_taps) { + if (cpu_is_omap24xx()) { + if (width > maxsinglelinewidth) + DSSERR("Cannot scale max input width exceeded"); + *five_taps = false; + fclk = calc_fclk(channel, width, height, out_width, + out_height); + } else if (cpu_is_omap34xx()) { + if (width > (maxsinglelinewidth * 2)) { + DSSERR("Cannot setup scaling"); + DSSERR("width exceeds maximum width possible"); + return -EINVAL; + } + fclk = calc_fclk_five_taps(channel, width, height, out_width, + out_height, color_mode); + if (width > maxsinglelinewidth) { + if (height > out_height && height < out_height * 2) + *five_taps = false; + else { + DSSERR("cannot setup scaling with five taps"); + return -EINVAL; + } + } + if (!*five_taps) + fclk = calc_fclk(channel, width, height, out_width, + out_height); + } else { + if (width > maxsinglelinewidth) { + DSSERR("Cannot scale width exceeds max line width"); + return -EINVAL; + } fclk = calc_fclk(channel, width, height, out_width, out_height); - - /* Try 5-tap filter if 3-tap fclk is too high */ - if (cpu_is_omap34xx() && height > out_height && - fclk > dispc_fclk_rate()) - *five_taps = true; - } - - if (width > (2048 >> *five_taps)) { - DSSERR("failed to set up scaling, fclk too low\n"); - return -EINVAL; } - if (*five_taps) - fclk = calc_fclk_five_taps(channel, width, height, - out_width, out_height, color_mode); - DSSDBG("required fclk rate = %lu Hz\n", fclk); DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); @@ -1771,11 +1757,10 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, } int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool ilace, enum omap_channel channel, bool replication, - u32 fifo_low, u32 fifo_high) + bool ilace, bool replication) { struct omap_overlay *ovl = omap_dss_get_overlay(plane); - bool five_taps = false; + bool five_taps = true; bool fieldmode = 0; int r, cconv = 0; unsigned offset0, offset1; @@ -1783,36 +1768,43 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, s32 pix_inc; u16 frame_height = oi->height; unsigned int field_offset = 0; + u16 outw, outh; + enum omap_channel channel; + + channel = dispc_ovl_get_channel_out(plane); DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d " - "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr, + "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", + plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, oi->color_mode, oi->rotation, - oi->mirror, ilace, channel, replication, fifo_low, fifo_high); + oi->mirror, ilace, channel, replication); if (oi->paddr == 0) return -EINVAL; - if (ilace && oi->height == oi->out_height) + outw = oi->out_width == 0 ? oi->width : oi->out_width; + outh = oi->out_height == 0 ? oi->height : oi->out_height; + + if (ilace && oi->height == outh) fieldmode = 1; if (ilace) { if (fieldmode) oi->height /= 2; oi->pos_y /= 2; - oi->out_height /= 2; + outh /= 2; DSSDBG("adjusting for ilace: height %d, pos_y %d, " "out_height %d\n", - oi->height, oi->pos_y, oi->out_height); + oi->height, oi->pos_y, outh); } if (!dss_feat_color_mode_supported(plane, oi->color_mode)) return -EINVAL; r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, - oi->out_width, oi->out_height, oi->color_mode, + outw, outh, oi->color_mode, &five_taps); if (r) return r; @@ -1830,10 +1822,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, * so the integer part must be added to the base address of the * bottom field. */ - if (!oi->height || oi->height == oi->out_height) + if (!oi->height || oi->height == outh) field_offset = 0; else - field_offset = oi->height / oi->out_height / 2; + field_offset = oi->height / outh / 2; } /* Fields are independent but interleaved in memory. */ @@ -1869,7 +1861,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, dispc_ovl_set_pix_inc(plane, pix_inc); DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, - oi->height, oi->out_width, oi->out_height); + oi->height, outw, outh); dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); @@ -1877,10 +1869,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { dispc_ovl_set_scaling(plane, oi->width, oi->height, - oi->out_width, oi->out_height, + outw, outh, ilace, five_taps, fieldmode, oi->color_mode, oi->rotation); - dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height); + dispc_ovl_set_vid_size(plane, outw, outh); dispc_ovl_set_vid_color_conv(plane, cconv); } @@ -1891,10 +1883,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); dispc_ovl_setup_global_alpha(plane, oi->global_alpha); - dispc_ovl_set_channel_out(plane, channel); - dispc_ovl_enable_replication(plane, replication); - dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); return 0; } @@ -1916,10 +1905,14 @@ static void dispc_disable_isr(void *data, u32 mask) static void _enable_lcd_out(enum omap_channel channel, bool enable) { - if (channel == OMAP_DSS_CHANNEL_LCD2) + if (channel == OMAP_DSS_CHANNEL_LCD2) { REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); - else + /* flush posted write */ + dispc_read_reg(DISPC_CONTROL2); + } else { REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); + dispc_read_reg(DISPC_CONTROL); + } } static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) @@ -1967,6 +1960,8 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) static void _enable_digit_out(bool enable) { REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); + /* flush posted write */ + dispc_read_reg(DISPC_CONTROL); } static void dispc_mgr_enable_digit_out(bool enable) @@ -2124,25 +2119,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) } -void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) +static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) { dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); } -u32 dispc_mgr_get_default_color(enum omap_channel channel) -{ - u32 l; - - BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && - channel != OMAP_DSS_CHANNEL_LCD && - channel != OMAP_DSS_CHANNEL_LCD2); - - l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); - - return l; -} - -void dispc_mgr_set_trans_key(enum omap_channel ch, +static void dispc_mgr_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { @@ -2156,26 +2138,7 @@ void dispc_mgr_set_trans_key(enum omap_channel ch, dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); } -void dispc_mgr_get_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type *type, - u32 *trans_key) -{ - if (type) { - if (ch == OMAP_DSS_CHANNEL_LCD) - *type = REG_GET(DISPC_CONFIG, 11, 11); - else if (ch == OMAP_DSS_CHANNEL_DIGIT) - *type = REG_GET(DISPC_CONFIG, 13, 13); - else if (ch == OMAP_DSS_CHANNEL_LCD2) - *type = REG_GET(DISPC_CONFIG2, 11, 11); - else - BUG(); - } - - if (trans_key) - *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); -} - -void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) +static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) { if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); @@ -2185,7 +2148,8 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); } -void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) +static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, + bool enable) { if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) return; @@ -2196,40 +2160,20 @@ void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); } -bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch) -{ - bool enabled; - - if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) - return false; - - if (ch == OMAP_DSS_CHANNEL_LCD) - enabled = REG_GET(DISPC_CONFIG, 18, 18); - else if (ch == OMAP_DSS_CHANNEL_DIGIT) - enabled = REG_GET(DISPC_CONFIG, 19, 19); - else - BUG(); - - return enabled; -} - -bool dispc_mgr_trans_key_enabled(enum omap_channel ch) +void dispc_mgr_setup(enum omap_channel channel, + struct omap_overlay_manager_info *info) { - bool enabled; - - if (ch == OMAP_DSS_CHANNEL_LCD) - enabled = REG_GET(DISPC_CONFIG, 10, 10); - else if (ch == OMAP_DSS_CHANNEL_DIGIT) - enabled = REG_GET(DISPC_CONFIG, 12, 12); - else if (ch == OMAP_DSS_CHANNEL_LCD2) - enabled = REG_GET(DISPC_CONFIG2, 10, 10); - else - BUG(); - - return enabled; + dispc_mgr_set_default_color(channel, info->default_color); + dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); + dispc_mgr_enable_trans_key(channel, info->trans_enabled); + dispc_mgr_enable_alpha_fixed_zorder(channel, + info->partial_alpha_enabled); + if (dss_has_feature(FEAT_CPR)) { + dispc_mgr_enable_cpr(channel, info->cpr_enable); + dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); + } } - void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -3184,7 +3128,8 @@ static void dispc_error_worker(struct work_struct *work) for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { struct omap_overlay_manager *mgr; mgr = omap_dss_get_overlay_manager(i); - mgr->device->driver->disable(mgr->device); + if (mgr->device && mgr->device->driver) + mgr->device->driver->disable(mgr->device); } } diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index c06efc38983e..5836bd1650f9 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -97,6 +97,17 @@ #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ DISPC_PRELOAD_OFFSET(n)) +/* DISPC up/downsampling FIR filter coefficient structure */ +struct dispc_coef { + s8 hc4_vc22; + s8 hc3_vc2; + u8 hc2_vc1; + s8 hc1_vc0; + s8 hc0_vc00; +}; + +const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps); + /* DISPC manager/channel specific registers */ static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) { diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c new file mode 100644 index 000000000000..069bccbb3f12 --- /dev/null +++ b/drivers/video/omap2/dss/dispc_coefs.c @@ -0,0 +1,326 @@ +/* + * linux/drivers/video/omap2/dss/dispc_coefs.c + * + * Copyright (C) 2011 Texas Instruments + * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <video/omapdss.h> +#include "dispc.h" + +#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) + +static const struct dispc_coef coef3_M8[8] = { + { 0, 0, 128, 0, 0 }, + { 0, -4, 123, 9, 0 }, + { 0, -4, 108, 87, 0 }, + { 0, -2, 87, 43, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 43, 87, -2, 0 }, + { 0, 24, 108, -4, 0 }, + { 0, 9, 123, -4, 0 }, +}; + +static const struct dispc_coef coef3_M9[8] = { + { 0, 6, 116, 6, 0 }, + { 0, 0, 112, 16, 0 }, + { 0, -2, 100, 30, 0 }, + { 0, -2, 83, 47, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 47, 83, -2, 0 }, + { 0, 30, 100, -2, 0 }, + { 0, 16, 112, 0, 0 }, +}; + +static const struct dispc_coef coef3_M10[8] = { + { 0, 10, 108, 10, 0 }, + { 0, 3, 104, 21, 0 }, + { 0, 0, 94, 34, 0 }, + { 0, -1, 80, 49, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 49, 80, -1, 0 }, + { 0, 34, 94, 0, 0 }, + { 0, 21, 104, 3, 0 }, +}; + +static const struct dispc_coef coef3_M11[8] = { + { 0, 14, 100, 14, 0 }, + { 0, 6, 98, 24, 0 }, + { 0, 2, 90, 36, 0 }, + { 0, 0, 78, 50, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 50, 78, 0, 0 }, + { 0, 36, 90, 2, 0 }, + { 0, 24, 98, 6, 0 }, +}; + +static const struct dispc_coef coef3_M12[8] = { + { 0, 16, 96, 16, 0 }, + { 0, 9, 93, 26, 0 }, + { 0, 4, 86, 38, 0 }, + { 0, 1, 76, 51, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 51, 76, 1, 0 }, + { 0, 38, 86, 4, 0 }, + { 0, 26, 93, 9, 0 }, +}; + +static const struct dispc_coef coef3_M13[8] = { + { 0, 18, 92, 18, 0 }, + { 0, 10, 90, 28, 0 }, + { 0, 5, 83, 40, 0 }, + { 0, 1, 75, 52, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 52, 75, 1, 0 }, + { 0, 40, 83, 5, 0 }, + { 0, 28, 90, 10, 0 }, +}; + +static const struct dispc_coef coef3_M14[8] = { + { 0, 20, 88, 20, 0 }, + { 0, 12, 86, 30, 0 }, + { 0, 6, 81, 41, 0 }, + { 0, 2, 74, 52, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 52, 74, 2, 0 }, + { 0, 41, 81, 6, 0 }, + { 0, 30, 86, 12, 0 }, +}; + +static const struct dispc_coef coef3_M16[8] = { + { 0, 22, 84, 22, 0 }, + { 0, 14, 82, 32, 0 }, + { 0, 8, 78, 42, 0 }, + { 0, 3, 72, 53, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 53, 72, 3, 0 }, + { 0, 42, 78, 8, 0 }, + { 0, 32, 82, 14, 0 }, +}; + +static const struct dispc_coef coef3_M19[8] = { + { 0, 24, 80, 24, 0 }, + { 0, 16, 79, 33, 0 }, + { 0, 9, 76, 43, 0 }, + { 0, 4, 70, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 70, 4, 0 }, + { 0, 43, 76, 9, 0 }, + { 0, 33, 79, 16, 0 }, +}; + +static const struct dispc_coef coef3_M22[8] = { + { 0, 25, 78, 25, 0 }, + { 0, 17, 77, 34, 0 }, + { 0, 10, 74, 44, 0 }, + { 0, 5, 69, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 69, 5, 0 }, + { 0, 44, 74, 10, 0 }, + { 0, 34, 77, 17, 0 }, +}; + +static const struct dispc_coef coef3_M26[8] = { + { 0, 26, 76, 26, 0 }, + { 0, 19, 74, 35, 0 }, + { 0, 11, 72, 45, 0 }, + { 0, 5, 69, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 69, 5, 0 }, + { 0, 45, 72, 11, 0 }, + { 0, 35, 74, 19, 0 }, +}; + +static const struct dispc_coef coef3_M32[8] = { + { 0, 27, 74, 27, 0 }, + { 0, 19, 73, 36, 0 }, + { 0, 12, 71, 45, 0 }, + { 0, 6, 68, 54, 0 }, + { 0, 64, 64, 0, 0 }, + { 0, 54, 68, 6, 0 }, + { 0, 45, 71, 12, 0 }, + { 0, 36, 73, 19, 0 }, +}; + +static const struct dispc_coef coef5_M8[8] = { + { 0, 0, 128, 0, 0 }, + { -2, 14, 125, -10, 1 }, + { -6, 33, 114, -15, 2 }, + { -10, 55, 98, -16, 1 }, + { 0, -14, 78, 78, -14 }, + { 1, -16, 98, 55, -10 }, + { 2, -15, 114, 33, -6 }, + { 1, -10, 125, 14, -2 }, +}; + +static const struct dispc_coef coef5_M9[8] = { + { -3, 10, 114, 10, -3 }, + { -6, 24, 110, 0, -1 }, + { -8, 40, 103, -7, 0 }, + { -11, 58, 91, -11, 1 }, + { 0, -12, 76, 76, -12 }, + { 1, -11, 91, 58, -11 }, + { 0, -7, 103, 40, -8 }, + { -1, 0, 111, 24, -6 }, +}; + +static const struct dispc_coef coef5_M10[8] = { + { -4, 18, 100, 18, -4 }, + { -6, 30, 99, 8, -3 }, + { -8, 44, 93, 0, -1 }, + { -9, 58, 84, -5, 0 }, + { 0, -8, 72, 72, -8 }, + { 0, -5, 84, 58, -9 }, + { -1, 0, 93, 44, -8 }, + { -3, 8, 99, 30, -6 }, +}; + +static const struct dispc_coef coef5_M11[8] = { + { -5, 23, 92, 23, -5 }, + { -6, 34, 90, 13, -3 }, + { -6, 45, 85, 6, -2 }, + { -6, 57, 78, 0, -1 }, + { 0, -4, 68, 68, -4 }, + { -1, 0, 78, 57, -6 }, + { -2, 6, 85, 45, -6 }, + { -3, 13, 90, 34, -6 }, +}; + +static const struct dispc_coef coef5_M12[8] = { + { -4, 26, 84, 26, -4 }, + { -5, 36, 82, 18, -3 }, + { -4, 46, 78, 10, -2 }, + { -3, 55, 72, 5, -1 }, + { 0, 0, 64, 64, 0 }, + { -1, 5, 72, 55, -3 }, + { -2, 10, 78, 46, -4 }, + { -3, 18, 82, 36, -5 }, +}; + +static const struct dispc_coef coef5_M13[8] = { + { -3, 28, 78, 28, -3 }, + { -3, 37, 76, 21, -3 }, + { -2, 45, 73, 14, -2 }, + { 0, 53, 68, 8, -1 }, + { 0, 3, 61, 61, 3 }, + { -1, 8, 68, 53, 0 }, + { -2, 14, 73, 45, -2 }, + { -3, 21, 76, 37, -3 }, +}; + +static const struct dispc_coef coef5_M14[8] = { + { -2, 30, 72, 30, -2 }, + { -1, 37, 71, 23, -2 }, + { 0, 45, 69, 16, -2 }, + { 3, 52, 64, 10, -1 }, + { 0, 6, 58, 58, 6 }, + { -1, 10, 64, 52, 3 }, + { -2, 16, 69, 45, 0 }, + { -2, 23, 71, 37, -1 }, +}; + +static const struct dispc_coef coef5_M16[8] = { + { 0, 31, 66, 31, 0 }, + { 1, 38, 65, 25, -1 }, + { 3, 44, 62, 20, -1 }, + { 6, 49, 59, 14, 0 }, + { 0, 10, 54, 54, 10 }, + { 0, 14, 59, 49, 6 }, + { -1, 20, 62, 44, 3 }, + { -1, 25, 65, 38, 1 }, +}; + +static const struct dispc_coef coef5_M19[8] = { + { 3, 32, 58, 32, 3 }, + { 4, 38, 58, 27, 1 }, + { 7, 42, 55, 23, 1 }, + { 10, 46, 54, 18, 0 }, + { 0, 14, 50, 50, 14 }, + { 0, 18, 54, 46, 10 }, + { 1, 23, 55, 42, 7 }, + { 1, 27, 58, 38, 4 }, +}; + +static const struct dispc_coef coef5_M22[8] = { + { 4, 33, 54, 33, 4 }, + { 6, 37, 54, 28, 3 }, + { 9, 41, 53, 24, 1 }, + { 12, 45, 51, 20, 0 }, + { 0, 16, 48, 48, 16 }, + { 0, 20, 51, 45, 12 }, + { 1, 24, 53, 41, 9 }, + { 3, 28, 54, 37, 6 }, +}; + +static const struct dispc_coef coef5_M26[8] = { + { 6, 33, 50, 33, 6 }, + { 8, 36, 51, 29, 4 }, + { 11, 40, 50, 25, 2 }, + { 14, 43, 48, 22, 1 }, + { 0, 18, 46, 46, 18 }, + { 1, 22, 48, 43, 14 }, + { 2, 25, 50, 40, 11 }, + { 4, 29, 51, 36, 8 }, +}; + +static const struct dispc_coef coef5_M32[8] = { + { 7, 33, 48, 33, 7 }, + { 10, 36, 48, 29, 5 }, + { 13, 39, 47, 26, 3 }, + { 16, 42, 46, 23, 1 }, + { 0, 19, 45, 45, 19 }, + { 1, 23, 46, 42, 16 }, + { 3, 26, 47, 39, 13 }, + { 5, 29, 48, 36, 10 }, +}; + +const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps) +{ + int i; + static const struct { + int Mmin; + int Mmax; + const struct dispc_coef *coef_3; + const struct dispc_coef *coef_5; + } coefs[] = { + { 27, 32, coef3_M32, coef5_M32 }, + { 23, 26, coef3_M26, coef5_M26 }, + { 20, 22, coef3_M22, coef5_M22 }, + { 17, 19, coef3_M19, coef5_M19 }, + { 15, 16, coef3_M16, coef5_M16 }, + { 14, 14, coef3_M14, coef5_M14 }, + { 13, 13, coef3_M13, coef5_M13 }, + { 12, 12, coef3_M12, coef5_M12 }, + { 11, 11, coef3_M11, coef5_M11 }, + { 10, 10, coef3_M10, coef5_M10 }, + { 9, 9, coef3_M9, coef5_M9 }, + { 4, 8, coef3_M8, coef5_M8 }, + /* + * When upscaling more than two times, blockiness and outlines + * around the image are observed when M8 tables are used. M11, + * M16 and M19 tables are used to prevent this. + */ + { 3, 3, coef3_M11, coef5_M11 }, + { 2, 2, coef3_M16, coef5_M16 }, + { 0, 1, coef3_M19, coef5_M19 }, + }; + + inc /= 128; + for (i = 0; i < ARRAY_LEN(coefs); ++i) + if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) + return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; + return NULL; +} diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 976ac23dcd0c..395d658a94fc 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -223,10 +223,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err_mgr_enable; return 0; +err_mgr_enable: err_set_mode: if (dpi_use_dsi_pll(dssdev)) dsi_pll_uninit(dpi.dsidev, true); @@ -249,7 +252,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 5abf8e7e7456..d4d676c82c12 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -203,6 +203,21 @@ struct dsi_reg { u16 idx; }; typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); #define DSI_MAX_NR_ISRS 2 +#define DSI_MAX_NR_LANES 5 + +enum dsi_lane_function { + DSI_LANE_UNUSED = 0, + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, +}; + +struct dsi_lane_config { + enum dsi_lane_function function; + u8 polarity; +}; struct dsi_isr_data { omap_dsi_isr_t isr; @@ -223,24 +238,6 @@ enum dsi_vc_source { DSI_VC_SOURCE_VP, }; -enum dsi_lane { - DSI_CLK_P = 1 << 0, - DSI_CLK_N = 1 << 1, - DSI_DATA1_P = 1 << 2, - DSI_DATA1_N = 1 << 3, - DSI_DATA2_P = 1 << 4, - DSI_DATA2_N = 1 << 5, - DSI_DATA3_P = 1 << 6, - DSI_DATA3_N = 1 << 7, - DSI_DATA4_P = 1 << 8, - DSI_DATA4_N = 1 << 9, -}; - -struct dsi_update_region { - u16 x, y, w, h; - struct omap_dss_device *device; -}; - struct dsi_irq_stats { unsigned long last_reset; unsigned irq_count; @@ -290,7 +287,9 @@ struct dsi_data { struct dsi_isr_tables isr_tables_copy; int update_channel; - struct dsi_update_region update_region; +#ifdef DEBUG + unsigned update_bytes; +#endif bool te_enabled; bool ulps_enabled; @@ -327,7 +326,10 @@ struct dsi_data { unsigned long fint_min, fint_max; unsigned long lpdiv_max; - int num_data_lanes; + unsigned num_lanes_supported; + + struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; + unsigned num_lanes_used; unsigned scp_clk_refcount; }; @@ -340,8 +342,8 @@ struct dsi_packet_sent_handler_data { static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; #ifdef DEBUG -static unsigned int dsi_perf; -module_param_named(dsi_perf, dsi_perf, bool, 0644); +static bool dsi_perf; +module_param(dsi_perf, bool, 0644); #endif static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev) @@ -413,14 +415,29 @@ static void dsi_completion_handler(void *data, u32 mask) static inline int wait_for_bit_change(struct platform_device *dsidev, const struct dsi_reg idx, int bitnum, int value) { - int t = 100000; + unsigned long timeout; + ktime_t wait; + int t; - while (REG_GET(dsidev, idx, bitnum, bitnum) != value) { - if (--t == 0) - return !value; + /* first busyloop to see if the bit changes right away */ + t = 100; + while (t-- > 0) { + if (REG_GET(dsidev, idx, bitnum, bitnum) == value) + return value; } - return value; + /* then loop for 500ms, sleeping for 1ms in between */ + timeout = jiffies + msecs_to_jiffies(500); + while (time_before(jiffies, timeout)) { + if (REG_GET(dsidev, idx, bitnum, bitnum) == value) + return value; + + wait = ns_to_ktime(1000 * 1000); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_hrtimeout(&wait, HRTIMER_MODE_REL); + } + + return !value; } u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) @@ -454,7 +471,6 @@ static void dsi_perf_mark_start(struct platform_device *dsidev) static void dsi_perf_show(struct platform_device *dsidev, const char *name) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_device *dssdev = dsi->update_region.device; ktime_t t, setup_time, trans_time; u32 total_bytes; u32 setup_us, trans_us, total_us; @@ -476,9 +492,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) total_us = setup_us + trans_us; - total_bytes = dsi->update_region.w * - dsi->update_region.h * - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + total_bytes = dsi->update_bytes; printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " "%u bytes, %u kbytes/sec\n", @@ -1720,17 +1734,19 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", cinfo->clkin4ddr, cinfo->regm); - seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", - dss_get_generic_clk_source_name(dispc_clk_src), - dss_feat_get_clk_source_name(dispc_clk_src), + seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n", + dss_feat_get_clk_source_name(dsi_module == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), cinfo->dsi_pll_hsdiv_dispc_clk, cinfo->regm_dispc, dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? "off" : "on"); - seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", - dss_get_generic_clk_source_name(dsi_clk_src), - dss_feat_get_clk_source_name(dsi_clk_src), + seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n", + dss_feat_get_clk_source_name(dsi_module == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), cinfo->dsi_pll_hsdiv_dsi_clk, cinfo->regm_dsi, dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? @@ -2029,34 +2045,6 @@ static int dsi_cio_power(struct platform_device *dsidev, return 0; } -/* Number of data lanes present on DSI interface */ -static inline int dsi_get_num_data_lanes(struct platform_device *dsidev) -{ - /* DSI on OMAP3 doesn't have register DSI_GNQ, set number - * of data lanes as 2 by default */ - if (dss_has_feature(FEAT_DSI_GNQ)) - return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */ - else - return 2; -} - -/* Number of data lanes used by the dss device */ -static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev) -{ - int num_data_lanes = 0; - - if (dssdev->phy.dsi.data1_lane != 0) - num_data_lanes++; - if (dssdev->phy.dsi.data2_lane != 0) - num_data_lanes++; - if (dssdev->phy.dsi.data3_lane != 0) - num_data_lanes++; - if (dssdev->phy.dsi.data4_lane != 0) - num_data_lanes++; - - return num_data_lanes; -} - static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) { int val; @@ -2088,59 +2076,112 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) } } -static void dsi_set_lane_config(struct omap_dss_device *dssdev) +static int dsi_parse_lane_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - u32 r; - int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + u8 lanes[DSI_MAX_NR_LANES]; + u8 polarities[DSI_MAX_NR_LANES]; + int num_lanes, i; + + static const enum dsi_lane_function functions[] = { + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, + }; + + lanes[0] = dssdev->phy.dsi.clk_lane; + lanes[1] = dssdev->phy.dsi.data1_lane; + lanes[2] = dssdev->phy.dsi.data2_lane; + lanes[3] = dssdev->phy.dsi.data3_lane; + lanes[4] = dssdev->phy.dsi.data4_lane; + polarities[0] = dssdev->phy.dsi.clk_pol; + polarities[1] = dssdev->phy.dsi.data1_pol; + polarities[2] = dssdev->phy.dsi.data2_pol; + polarities[3] = dssdev->phy.dsi.data3_pol; + polarities[4] = dssdev->phy.dsi.data4_pol; - int clk_lane = dssdev->phy.dsi.clk_lane; - int data1_lane = dssdev->phy.dsi.data1_lane; - int data2_lane = dssdev->phy.dsi.data2_lane; - int clk_pol = dssdev->phy.dsi.clk_pol; - int data1_pol = dssdev->phy.dsi.data1_pol; - int data2_pol = dssdev->phy.dsi.data2_pol; + num_lanes = 0; + + for (i = 0; i < dsi->num_lanes_supported; ++i) + dsi->lanes[i].function = DSI_LANE_UNUSED; + + for (i = 0; i < dsi->num_lanes_supported; ++i) { + int num; + + if (lanes[i] == DSI_LANE_UNUSED) + break; + + num = lanes[i] - 1; + + if (num >= dsi->num_lanes_supported) + return -EINVAL; + + if (dsi->lanes[num].function != DSI_LANE_UNUSED) + return -EINVAL; + + dsi->lanes[num].function = functions[i]; + dsi->lanes[num].polarity = polarities[i]; + num_lanes++; + } + + if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported) + return -EINVAL; + + dsi->num_lanes_used = num_lanes; + + return 0; +} + +static int dsi_set_lane_config(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + static const u8 offsets[] = { 0, 4, 8, 12, 16 }; + static const enum dsi_lane_function functions[] = { + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, + }; + u32 r; + int i; r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); - r = FLD_MOD(r, clk_lane, 2, 0); - r = FLD_MOD(r, clk_pol, 3, 3); - r = FLD_MOD(r, data1_lane, 6, 4); - r = FLD_MOD(r, data1_pol, 7, 7); - r = FLD_MOD(r, data2_lane, 10, 8); - r = FLD_MOD(r, data2_pol, 11, 11); - if (num_data_lanes_dssdev > 2) { - int data3_lane = dssdev->phy.dsi.data3_lane; - int data3_pol = dssdev->phy.dsi.data3_pol; - - r = FLD_MOD(r, data3_lane, 14, 12); - r = FLD_MOD(r, data3_pol, 15, 15); + + for (i = 0; i < dsi->num_lanes_used; ++i) { + unsigned offset = offsets[i]; + unsigned polarity, lane_number; + unsigned t; + + for (t = 0; t < dsi->num_lanes_supported; ++t) + if (dsi->lanes[t].function == functions[i]) + break; + + if (t == dsi->num_lanes_supported) + return -EINVAL; + + lane_number = t; + polarity = dsi->lanes[t].polarity; + + r = FLD_MOD(r, lane_number + 1, offset + 2, offset); + r = FLD_MOD(r, polarity, offset + 3, offset + 3); } - if (num_data_lanes_dssdev > 3) { - int data4_lane = dssdev->phy.dsi.data4_lane; - int data4_pol = dssdev->phy.dsi.data4_pol; - r = FLD_MOD(r, data4_lane, 18, 16); - r = FLD_MOD(r, data4_pol, 19, 19); + /* clear the unused lanes */ + for (; i < dsi->num_lanes_supported; ++i) { + unsigned offset = offsets[i]; + + r = FLD_MOD(r, 0, offset + 2, offset); + r = FLD_MOD(r, 0, offset + 3, offset + 3); } - dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); - /* The configuration of the DSI complex I/O (number of data lanes, - position, differential order) should not be changed while - DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for - the hardware to take into account a new configuration of the complex - I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to - follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, - then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set - DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the - DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the - DSI complex I/O configuration is unknown. */ + dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); - /* - REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); - REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0); - REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); - REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); - */ + return 0; } static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) @@ -2230,49 +2271,28 @@ static void dsi_cio_timings(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); } +/* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, - enum dsi_lane lanes) + unsigned mask_p, unsigned mask_n) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int clk_lane = dssdev->phy.dsi.clk_lane; - int data1_lane = dssdev->phy.dsi.data1_lane; - int data2_lane = dssdev->phy.dsi.data2_lane; - int data3_lane = dssdev->phy.dsi.data3_lane; - int data4_lane = dssdev->phy.dsi.data4_lane; - int clk_pol = dssdev->phy.dsi.clk_pol; - int data1_pol = dssdev->phy.dsi.data1_pol; - int data2_pol = dssdev->phy.dsi.data2_pol; - int data3_pol = dssdev->phy.dsi.data3_pol; - int data4_pol = dssdev->phy.dsi.data4_pol; - - u32 l = 0; - u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26; - - if (lanes & DSI_CLK_P) - l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); - if (lanes & DSI_CLK_N) - l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0)); - - if (lanes & DSI_DATA1_P) - l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1)); - if (lanes & DSI_DATA1_N) - l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0)); - - if (lanes & DSI_DATA2_P) - l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1)); - if (lanes & DSI_DATA2_N) - l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0)); - - if (lanes & DSI_DATA3_P) - l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1)); - if (lanes & DSI_DATA3_N) - l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0)); - - if (lanes & DSI_DATA4_P) - l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1)); - if (lanes & DSI_DATA4_N) - l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0)); + int i; + u32 l; + u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; + + l = 0; + + for (i = 0; i < dsi->num_lanes_supported; ++i) { + unsigned p = dsi->lanes[i].polarity; + + if (mask_p & (1 << i)) + l |= 1 << (i * 2 + (p ? 0 : 1)); + + if (mask_n & (1 << i)) + l |= 1 << (i * 2 + (p ? 1 : 0)); + } + /* * Bits in REGLPTXSCPDAT4TO0DXDY: * 17: DY0 18: DX0 @@ -2305,51 +2325,40 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - int t; - int bits[3]; - bool in_use[3]; - - if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { - bits[0] = 28; - bits[1] = 27; - bits[2] = 26; - } else { - bits[0] = 24; - bits[1] = 25; - bits[2] = 26; - } - - in_use[0] = false; - in_use[1] = false; - in_use[2] = false; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int t, i; + bool in_use[DSI_MAX_NR_LANES]; + static const u8 offsets_old[] = { 28, 27, 26 }; + static const u8 offsets_new[] = { 24, 25, 26, 27, 28 }; + const u8 *offsets; + + if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) + offsets = offsets_old; + else + offsets = offsets_new; - if (dssdev->phy.dsi.clk_lane != 0) - in_use[dssdev->phy.dsi.clk_lane - 1] = true; - if (dssdev->phy.dsi.data1_lane != 0) - in_use[dssdev->phy.dsi.data1_lane - 1] = true; - if (dssdev->phy.dsi.data2_lane != 0) - in_use[dssdev->phy.dsi.data2_lane - 1] = true; + for (i = 0; i < dsi->num_lanes_supported; ++i) + in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED; t = 100000; while (true) { u32 l; - int i; int ok; l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); ok = 0; - for (i = 0; i < 3; ++i) { - if (!in_use[i] || (l & (1 << bits[i]))) + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (!in_use[i] || (l & (1 << offsets[i]))) ok++; } - if (ok == 3) + if (ok == dsi->num_lanes_supported) break; if (--t == 0) { - for (i = 0; i < 3; ++i) { - if (!in_use[i] || (l & (1 << bits[i]))) + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (!in_use[i] || (l & (1 << offsets[i]))) continue; DSSERR("CIO TXCLKESC%d domain not coming " \ @@ -2362,22 +2371,20 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) return 0; } +/* return bitmask of enabled lanes, lane0 being the lsb */ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) { - unsigned lanes = 0; + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned mask = 0; + int i; - if (dssdev->phy.dsi.clk_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1); - if (dssdev->phy.dsi.data1_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1); - if (dssdev->phy.dsi.data2_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1); - if (dssdev->phy.dsi.data3_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1); - if (dssdev->phy.dsi.data4_lane != 0) - lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1); + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (dsi->lanes[i].function != DSI_LANE_UNUSED) + mask |= 1 << i; + } - return lanes; + return mask; } static int dsi_cio_init(struct omap_dss_device *dssdev) @@ -2385,7 +2392,6 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); u32 l; DSSDBGF(); @@ -2407,7 +2413,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) goto err_scp_clk_dom; } - dsi_set_lane_config(dssdev); + r = dsi_set_lane_config(dssdev); + if (r) + goto err_scp_clk_dom; /* set TX STOP MODE timer to maximum for this operation */ l = dsi_read_reg(dsidev, DSI_TIMING1); @@ -2418,7 +2426,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_TIMING1, l); if (dsi->ulps_enabled) { - u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P; + unsigned mask_p; + int i; DSSDBG("manual ulps exit\n"); @@ -2427,16 +2436,19 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) * ULPS exit sequence, as after reset the DSS HW thinks * that we are not in ULPS mode, and refuses to send the * sequence. So we need to send the ULPS exit sequence - * manually. + * manually by setting positive lines high and negative lines + * low for 1ms. */ - if (num_data_lanes_dssdev > 2) - lane_mask |= DSI_DATA3_P; + mask_p = 0; - if (num_data_lanes_dssdev > 3) - lane_mask |= DSI_DATA4_P; + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (dsi->lanes[i].function == DSI_LANE_UNUSED) + continue; + mask_p |= 1 << i; + } - dsi_cio_enable_lane_override(dssdev, lane_mask); + dsi_cio_enable_lane_override(dssdev, mask_p, 0); } r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); @@ -2913,6 +2925,9 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ + /* flush posted write */ + dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); + return 0; } @@ -3513,7 +3528,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DECLARE_COMPLETION_ONSTACK(completion); - int r; + int r, i; + unsigned mask; DSSDBGF(); @@ -3524,9 +3540,11 @@ static int dsi_enter_ulps(struct platform_device *dsidev) if (dsi->ulps_enabled) return 0; + /* DDR_CLK_ALWAYS_ON */ if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { - DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n"); - return -EIO; + dsi_if_enable(dsidev, 0); + REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); + dsi_if_enable(dsidev, 1); } dsi_sync_vc(dsidev, 0); @@ -3556,10 +3574,19 @@ static int dsi_enter_ulps(struct platform_device *dsidev) if (r) return r; + mask = 0; + + for (i = 0; i < dsi->num_lanes_supported; ++i) { + if (dsi->lanes[i].function == DSI_LANE_UNUSED) + continue; + mask |= 1 << i; + } /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ /* LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), - 7, 5); + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); + + /* flush posted write and wait for SCP interface to finish the write */ + dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); if (wait_for_completion_timeout(&completion, msecs_to_jiffies(1000)) == 0) { @@ -3572,8 +3599,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); /* Reset LANEx_ULPS_SIG2 */ - REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), - 7, 5); + REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); + + /* flush posted write and wait for SCP interface to finish the write */ + dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); @@ -3836,6 +3865,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) static void dsi_proto_timings(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; unsigned tclk_pre, tclk_post; unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; @@ -3843,7 +3873,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) unsigned ddr_clk_pre, ddr_clk_post; unsigned enter_hs_mode_lat, exit_hs_mode_lat; unsigned ths_eot; - int ndl = dsi_get_num_data_lanes_dssdev(dssdev); + int ndl = dsi->num_lanes_used - 1; u32 r; r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); @@ -3945,68 +3975,82 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) } } -int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel) +int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); u8 data_type; u16 word_count; + int r; - switch (dssdev->panel.dsi_pix_fmt) { - case OMAP_DSS_DSI_FMT_RGB888: - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; - break; - case OMAP_DSS_DSI_FMT_RGB666: - data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; - break; - case OMAP_DSS_DSI_FMT_RGB666_PACKED: - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; - break; - case OMAP_DSS_DSI_FMT_RGB565: - data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; - break; - default: - BUG(); - }; + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + switch (dssdev->panel.dsi_pix_fmt) { + case OMAP_DSS_DSI_FMT_RGB888: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; + break; + case OMAP_DSS_DSI_FMT_RGB666: + data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; + break; + case OMAP_DSS_DSI_FMT_RGB666_PACKED: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; + break; + case OMAP_DSS_DSI_FMT_RGB565: + data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; + break; + default: + BUG(); + }; - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); - /* MODE, 1 = video mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); + /* MODE, 1 = video mode */ + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); - word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); + word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); - dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); + dsi_vc_write_long_header(dsidev, channel, data_type, + word_count, 0); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsidev, channel, true); + dsi_if_enable(dsidev, true); + } - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) { + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); + } + + return r; + } return 0; } -EXPORT_SYMBOL(dsi_video_mode_enable); +EXPORT_SYMBOL(dsi_enable_video_output); -void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel) +void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); - /* MODE, 0 = command mode */ - REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); + /* MODE, 0 = command mode */ + REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); - dsi_vc_enable(dsidev, channel, true); - dsi_if_enable(dsidev, true); + dsi_vc_enable(dsidev, channel, true); + dsi_if_enable(dsidev, true); + } - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); } -EXPORT_SYMBOL(dsi_video_mode_disable); +EXPORT_SYMBOL(dsi_disable_video_output); static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h) + u16 w, u16 h) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -4021,8 +4065,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, const unsigned channel = dsi->update_channel; const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); - DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", - x, y, w, h); + DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); @@ -4070,7 +4113,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_start_update(dssdev); + dss_mgr_start_update(dssdev->manager); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4146,66 +4189,27 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) #endif } -int omap_dsi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h, - bool enlarge_update_area) +int omap_dsi_update(struct omap_dss_device *dssdev, int channel, + void (*callback)(int, void *), void *data) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 dw, dh; - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - if (*x > dw || *y > dh) - return -EINVAL; - - if (*x + *w > dw) - return -EINVAL; - - if (*y + *h > dh) - return -EINVAL; - - if (*w == 1) - return -EINVAL; - - if (*w == 0 || *h == 0) - return -EINVAL; - dsi_perf_mark_setup(dsidev); - dss_setup_partial_planes(dssdev, x, y, w, h, - enlarge_update_area); - dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); - - return 0; -} -EXPORT_SYMBOL(omap_dsi_prepare_update); - -int omap_dsi_update(struct omap_dss_device *dssdev, - int channel, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(int, void *), void *data) -{ - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - dsi->update_channel = channel; - /* OMAP DSS cannot send updates of odd widths. - * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON - * here to make sure we catch erroneous updates. Otherwise we'll only - * see rather obscure HW error happening, as DSS halts. */ - BUG_ON(x % 2 == 1); - dsi->framedone_callback = callback; dsi->framedone_data = data; - dsi->update_region.x = x; - dsi->update_region.y = y; - dsi->update_region.w = w; - dsi->update_region.h = h; - dsi->update_region.device = dssdev; + dssdev->driver->get_resolution(dssdev, &dw, &dh); - dsi_update_screen_dispc(dssdev, x, y, w, h); +#ifdef DEBUG + dsi->update_bytes = dw * dh * + dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; +#endif + dsi_update_screen_dispc(dssdev, dw, dh); return 0; } @@ -4218,6 +4222,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) int r; if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + u16 dw, dh; u32 irq; struct omap_video_timings timings = { .hsw = 1, @@ -4228,6 +4233,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) .vbp = 0, }; + dssdev->driver->get_resolution(dssdev, &dw, &dh); + timings.x_res = dw; + timings.y_res = dh; + irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; @@ -4330,6 +4339,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) int dsi_module = dsi_get_dsidev_id(dsidev); int r; + r = dsi_parse_lane_config(dssdev); + if (r) { + DSSERR("illegal lane config"); + goto err0; + } + r = dsi_pll_init(dsidev, true, true); if (r) goto err0; @@ -4521,7 +4536,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int dsi_module = dsi_get_dsidev_id(dsidev); DSSDBG("DSI init\n"); @@ -4543,12 +4557,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) dsi->vdds_dsi_reg = vdds_dsi; } - if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) { - DSSERR("DSI%d can't support more than %d data lanes\n", - dsi_module + 1, dsi->num_data_lanes); - return -EINVAL; - } - return 0; } @@ -4771,7 +4779,13 @@ static int omap_dsihw_probe(struct platform_device *dsidev) dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); + /* DSI on OMAP3 doesn't have register DSI_GNQ, set number + * of data to 3 by default */ + if (dss_has_feature(FEAT_DSI_GNQ)) + /* NB_DATA_LANES */ + dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); + else + dsi->num_lanes_supported = 3; dsi_runtime_put(dsidev); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 6308fc59fc9e..32ff69fb3333 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -28,7 +28,7 @@ #endif #ifdef DEBUG -extern unsigned int dss_debug; +extern bool dss_debug; #ifdef DSS_SUBSYS_NAME #define DSSDBG(format, ...) \ if (dss_debug) \ @@ -163,6 +163,34 @@ struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); +/* apply */ +void dss_apply_init(void); +int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr); +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); +void dss_mgr_start_update(struct omap_overlay_manager *mgr); +int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); + +int dss_mgr_enable(struct omap_overlay_manager *mgr); +void dss_mgr_disable(struct omap_overlay_manager *mgr); +int dss_mgr_set_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info); +void dss_mgr_get_info(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info); +int dss_mgr_set_device(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev); +int dss_mgr_unset_device(struct omap_overlay_manager *mgr); + +bool dss_ovl_is_enabled(struct omap_overlay *ovl); +int dss_ovl_enable(struct omap_overlay *ovl); +int dss_ovl_disable(struct omap_overlay *ovl); +int dss_ovl_set_info(struct omap_overlay *ovl, + struct omap_overlay_info *info); +void dss_ovl_get_info(struct omap_overlay *ovl, + struct omap_overlay_info *info); +int dss_ovl_set_manager(struct omap_overlay *ovl, + struct omap_overlay_manager *mgr); +int dss_ovl_unset_manager(struct omap_overlay *ovl); + /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); @@ -181,21 +209,22 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, /* manager */ int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); -void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h, - bool enlarge_update_area); -void dss_start_update(struct omap_dss_device *dssdev); +int dss_mgr_simple_check(struct omap_overlay_manager *mgr, + const struct omap_overlay_manager_info *info); +int dss_mgr_check(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, + struct omap_overlay_manager_info *info, + struct omap_overlay_info **overlay_infos); /* overlay */ void dss_init_overlays(struct platform_device *pdev); void dss_uninit_overlays(struct platform_device *pdev); -int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev); void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); -#ifdef L4_EXAMPLE -void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr); -#endif void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); +int dss_ovl_simple_check(struct omap_overlay *ovl, + const struct omap_overlay_info *info); +int dss_ovl_check(struct omap_overlay *ovl, + struct omap_overlay_info *info, struct omap_dss_device *dssdev); /* DSS */ int dss_init_platform_driver(void); @@ -399,21 +428,22 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo); +void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); u32 dispc_ovl_get_fifo_size(enum omap_plane plane); u32 dispc_ovl_get_burst_size(enum omap_plane plane); int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool ilace, enum omap_channel channel, bool replication, - u32 fifo_low, u32 fifo_high); + bool ilace, bool replication); int dispc_ovl_enable(enum omap_plane plane, bool enable); - +void dispc_ovl_set_channel_out(enum omap_plane plane, + enum omap_channel channel); void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); -void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable); -void dispc_mgr_set_cpr_coef(enum omap_channel channel, - struct omap_dss_cpr_coefs *coefs); +u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); +u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); bool dispc_mgr_go_busy(enum omap_channel channel); void dispc_mgr_go(enum omap_channel channel); +bool dispc_mgr_is_enabled(enum omap_channel channel); void dispc_mgr_enable(enum omap_channel channel, bool enable); bool dispc_mgr_is_channel_enabled(enum omap_channel channel); void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); @@ -421,18 +451,6 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); void dispc_mgr_set_lcd_display_type(enum omap_channel channel, enum omap_lcd_display_type type); -void dispc_mgr_set_default_color(enum omap_channel channel, u32 color); -u32 dispc_mgr_get_default_color(enum omap_channel channel); -void dispc_mgr_set_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type type, - u32 trans_key); -void dispc_mgr_get_trans_key(enum omap_channel ch, - enum omap_dss_trans_key_type *type, - u32 *trans_key); -void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable); -void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable); -bool dispc_mgr_trans_key_enabled(enum omap_channel ch); -bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch); void dispc_mgr_set_lcd_timings(enum omap_channel channel, struct omap_video_timings *timings); void dispc_mgr_set_pol_freq(enum omap_channel channel, @@ -443,6 +461,8 @@ int dispc_mgr_set_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); int dispc_mgr_get_clock_div(enum omap_channel channel, struct dispc_clock_info *cinfo); +void dispc_mgr_setup(enum omap_channel channel, + struct omap_overlay_manager_info *info); /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index b402699168a5..afcb59301c37 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, + /* + * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC + * scaler cannot scale a image with width more than 768. + */ + [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, }; static const struct dss_param_range omap3_dss_param_range[] = { @@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, }; static const struct dss_param_range omap4_dss_param_range[] = { @@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, }; /* OMAP2 DSS Features */ @@ -465,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { .dump_core = ti_hdmi_4xxx_core_dump, .dump_pll = ti_hdmi_4xxx_pll_dump, .dump_phy = ti_hdmi_4xxx_phy_dump, +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + .audio_enable = ti_hdmi_4xxx_wp_audio_enable, +#endif }; diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 6a6c05dd45ce..cd833bbaac3d 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -86,6 +86,7 @@ enum dss_range_param { FEAT_PARAM_DSIPLL_FINT, FEAT_PARAM_DSIPLL_LPDIV, FEAT_PARAM_DOWNSCALE, + FEAT_PARAM_LINEWIDTH, }; /* DSS Feature Functions */ diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index c56378c555b0..b4c270edb915 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -333,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) if (r) return r; - dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); + dss_mgr_disable(dssdev->manager); p = &dssdev->panel.timings; @@ -387,9 +387,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); - dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err_mgr_enable; return 0; + +err_mgr_enable: + hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); + hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); + hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err: hdmi_runtime_put(); return -EIO; @@ -397,7 +404,7 @@ err: static void hdmi_power_off(struct omap_dss_device *dssdev) { - dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); + dss_mgr_disable(dssdev->manager); hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); @@ -554,11 +561,44 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) -static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data, - struct snd_pcm_substream *substream, +static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct platform_device *pdev = to_platform_device(codec->dev); + struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); + int err = 0; + + if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) { + dev_err(&pdev->dev, "Cannot enable/disable audio\n"); + return -ENODEV; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ip_data->ops->audio_enable(ip_data, true); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ip_data->ops->audio_enable(ip_data, false); + break; + default: + err = -EINVAL; + } + return err; +} + +static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); struct hdmi_audio_format audio_format; struct hdmi_audio_dma audio_dma; struct hdmi_core_audio_config core_cfg; @@ -698,7 +738,16 @@ static int hdmi_audio_startup(struct snd_pcm_substream *substream, return 0; } +static int hdmi_audio_codec_probe(struct snd_soc_codec *codec) +{ + struct hdmi_ip_data *priv = &hdmi.ip_data; + + snd_soc_codec_set_drvdata(codec, priv); + return 0; +} + static struct snd_soc_codec_driver hdmi_audio_codec_drv = { + .probe = hdmi_audio_codec_probe, }; static struct snd_soc_dai_ops hdmi_audio_codec_ops = { diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 6e63845cc7d7..d1858e71c64e 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -26,17 +26,15 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/spinlock.h> #include <linux/jiffies.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" static int num_managers; -static struct list_head manager_list; +static struct omap_overlay_manager *managers; static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) { @@ -106,7 +104,11 @@ put_device: static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color); + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); } static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, @@ -144,8 +146,11 @@ static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, char *buf) { enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); - key_type = mgr->info.trans_key_type; + key_type = info.trans_key_type; BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); @@ -185,7 +190,11 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key); + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); } static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, @@ -217,7 +226,11 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled); + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); } static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, @@ -249,10 +262,14 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, static ssize_t manager_alpha_blending_enabled_show( struct omap_overlay_manager *mgr, char *buf) { + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); return snprintf(buf, PAGE_SIZE, "%d\n", - mgr->info.partial_alpha_enabled); + info.partial_alpha_enabled); } static ssize_t manager_alpha_blending_enabled_store( @@ -287,7 +304,11 @@ static ssize_t manager_alpha_blending_enabled_store( static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable); + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); } static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, @@ -469,143 +490,6 @@ static struct kobj_type manager_ktype = { .default_attrs = manager_sysfs_attrs, }; -/* - * We have 4 levels of cache for the dispc settings. First two are in SW and - * the latter two in HW. - * - * +--------------------+ - * |overlay/manager_info| - * +--------------------+ - * v - * apply() - * v - * +--------------------+ - * | dss_cache | - * +--------------------+ - * v - * configure() - * v - * +--------------------+ - * | shadow registers | - * +--------------------+ - * v - * VFP or lcd/digit_enable - * v - * +--------------------+ - * | registers | - * +--------------------+ - */ - -struct overlay_cache_data { - /* If true, cache changed, but not written to shadow registers. Set - * in apply(), cleared when registers written. */ - bool dirty; - /* If true, shadow registers contain changed values not yet in real - * registers. Set when writing to shadow registers, cleared at - * VSYNC/EVSYNC */ - bool shadow_dirty; - - bool enabled; - - struct omap_overlay_info info; - - enum omap_channel channel; - bool replication; - bool ilace; - - u32 fifo_low; - u32 fifo_high; -}; - -struct manager_cache_data { - /* If true, cache changed, but not written to shadow registers. Set - * in apply(), cleared when registers written. */ - bool dirty; - /* If true, shadow registers contain changed values not yet in real - * registers. Set when writing to shadow registers, cleared at - * VSYNC/EVSYNC */ - bool shadow_dirty; - - struct omap_overlay_manager_info info; - - bool manual_update; - bool do_manual_update; - - /* manual update region */ - u16 x, y, w, h; - - /* enlarge the update area if the update area contains scaled - * overlays */ - bool enlarge_update_area; -}; - -static struct { - spinlock_t lock; - struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; - struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; - - bool irq_enabled; -} dss_cache; - - - -static int omap_dss_set_device(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev) -{ - int i; - int r; - - if (dssdev->manager) { - DSSERR("display '%s' already has a manager '%s'\n", - dssdev->name, dssdev->manager->name); - return -EINVAL; - } - - if ((mgr->supported_displays & dssdev->type) == 0) { - DSSERR("display '%s' does not support manager '%s'\n", - dssdev->name, mgr->name); - return -EINVAL; - } - - for (i = 0; i < mgr->num_overlays; i++) { - struct omap_overlay *ovl = mgr->overlays[i]; - - if (ovl->manager != mgr || !ovl->info.enabled) - continue; - - r = dss_check_overlay(ovl, dssdev); - if (r) - return r; - } - - dssdev->manager = mgr; - mgr->device = dssdev; - mgr->device_changed = true; - - return 0; -} - -static int omap_dss_unset_device(struct omap_overlay_manager *mgr) -{ - if (!mgr->device) { - DSSERR("failed to unset display, display not set.\n"); - return -EINVAL; - } - - /* - * Don't allow currently enabled displays to have the overlay manager - * pulled out from underneath them - */ - if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) - return -EINVAL; - - mgr->device->manager = NULL; - mgr->device = NULL; - mgr->device_changed = true; - - return 0; -} - static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); @@ -624,1022 +508,169 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } -static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct manager_cache_data *mc; - u32 irq; - int r; - int i; - struct omap_dss_device *dssdev = mgr->device; - - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - return 0; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; - } - - mc = &dss_cache.manager_cache[mgr->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = mc->dirty; - shadow_dirty = mc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } - - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("mgr(%d)->wait_for_go() not finishing\n", - mgr->id); - r = 0; - break; - } - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; - - if (r) { - DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); - break; - } - } - - return r; -} - -int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) -{ - unsigned long timeout = msecs_to_jiffies(500); - struct overlay_cache_data *oc; - struct omap_dss_device *dssdev; - u32 irq; - int r; - int i; - - if (!ovl->manager) - return 0; - - dssdev = ovl->manager->device; - - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) - return 0; - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - } else { - irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? - DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; - } - - oc = &dss_cache.overlay_cache[ovl->id]; - i = 0; - while (1) { - unsigned long flags; - bool shadow_dirty, dirty; - - spin_lock_irqsave(&dss_cache.lock, flags); - dirty = oc->dirty; - shadow_dirty = oc->shadow_dirty; - spin_unlock_irqrestore(&dss_cache.lock, flags); - - if (!dirty && !shadow_dirty) { - r = 0; - break; - } - - /* 4 iterations is the worst case: - * 1 - initial iteration, dirty = true (between VFP and VSYNC) - * 2 - first VSYNC, dirty = true - * 3 - dirty = false, shadow_dirty = true - * 4 - shadow_dirty = false */ - if (i++ == 3) { - DSSERR("ovl(%d)->wait_for_go() not finishing\n", - ovl->id); - r = 0; - break; - } - - r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); - if (r == -ERESTARTSYS) - break; - - if (r) { - DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); - break; - } - } - - return r; -} - -static int overlay_enabled(struct omap_overlay *ovl) -{ - return ovl->info.enabled && ovl->manager && ovl->manager->device; -} - -/* Is rect1 a subset of rect2? */ -static bool rectangle_subset(int x1, int y1, int w1, int h1, - int x2, int y2, int w2, int h2) -{ - if (x1 < x2 || y1 < y2) - return false; - - if (x1 + w1 > x2 + w2) - return false; - - if (y1 + h1 > y2 + h2) - return false; - - return true; -} - -/* Do rect1 and rect2 overlap? */ -static bool rectangle_intersects(int x1, int y1, int w1, int h1, - int x2, int y2, int w2, int h2) -{ - if (x1 >= x2 + w2) - return false; - - if (x2 >= x1 + w1) - return false; - - if (y1 >= y2 + h2) - return false; - - if (y2 >= y1 + h1) - return false; - - return true; -} - -static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc) -{ - struct omap_overlay_info *oi = &oc->info; - - if (oi->out_width != 0 && oi->width != oi->out_width) - return true; - - if (oi->out_height != 0 && oi->height != oi->out_height) - return true; - - return false; -} - -static int configure_overlay(enum omap_plane plane) +int dss_init_overlay_managers(struct platform_device *pdev) { - struct overlay_cache_data *c; - struct manager_cache_data *mc; - struct omap_overlay_info *oi, new_oi; - struct omap_overlay_manager_info *mi; - u16 outw, outh; - u16 x, y, w, h; - u32 paddr; - int r; - u16 orig_w, orig_h, orig_outw, orig_outh; + int i, r; - DSSDBGF("%d", plane); + num_managers = dss_feat_get_num_mgrs(); - c = &dss_cache.overlay_cache[plane]; - oi = &c->info; + managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, + GFP_KERNEL); - if (!c->enabled) { - dispc_ovl_enable(plane, 0); - return 0; - } + BUG_ON(managers == NULL); - mc = &dss_cache.manager_cache[c->channel]; - mi = &mc->info; - - x = oi->pos_x; - y = oi->pos_y; - w = oi->width; - h = oi->height; - outw = oi->out_width == 0 ? oi->width : oi->out_width; - outh = oi->out_height == 0 ? oi->height : oi->out_height; - paddr = oi->paddr; - - orig_w = w; - orig_h = h; - orig_outw = outw; - orig_outh = outh; - - if (mc->manual_update && mc->do_manual_update) { - unsigned bpp; - unsigned scale_x_m = w, scale_x_d = outw; - unsigned scale_y_m = h, scale_y_d = outh; - - /* If the overlay is outside the update region, disable it */ - if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, - x, y, outw, outh)) { - dispc_ovl_enable(plane, 0); - return 0; - } + for (i = 0; i < num_managers; ++i) { + struct omap_overlay_manager *mgr = &managers[i]; - switch (oi->color_mode) { - case OMAP_DSS_COLOR_NV12: - bpp = 8; - break; - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_YUV2: - case OMAP_DSS_COLOR_UYVY: - case OMAP_DSS_COLOR_RGBA16: - case OMAP_DSS_COLOR_RGBX16: - case OMAP_DSS_COLOR_ARGB16_1555: - case OMAP_DSS_COLOR_XRGB16_1555: - bpp = 16; + switch (i) { + case 0: + mgr->name = "lcd"; + mgr->id = OMAP_DSS_CHANNEL_LCD; break; - - case OMAP_DSS_COLOR_RGB24P: - bpp = 24; + case 1: + mgr->name = "tv"; + mgr->id = OMAP_DSS_CHANNEL_DIGIT; break; - - case OMAP_DSS_COLOR_RGB24U: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - case OMAP_DSS_COLOR_RGBX32: - bpp = 32; + case 2: + mgr->name = "lcd2"; + mgr->id = OMAP_DSS_CHANNEL_LCD2; break; - - default: - BUG(); } - if (mc->x > oi->pos_x) { - x = 0; - outw -= (mc->x - oi->pos_x); - paddr += (mc->x - oi->pos_x) * - scale_x_m / scale_x_d * bpp / 8; - } else { - x = oi->pos_x - mc->x; - } - - if (mc->y > oi->pos_y) { - y = 0; - outh -= (mc->y - oi->pos_y); - paddr += (mc->y - oi->pos_y) * - scale_y_m / scale_y_d * - oi->screen_width * bpp / 8; - } else { - y = oi->pos_y - mc->y; - } - - if (mc->w < (x + outw)) - outw -= (x + outw) - (mc->w); - - if (mc->h < (y + outh)) - outh -= (y + outh) - (mc->h); - - w = w * outw / orig_outw; - h = h * outh / orig_outh; - - /* YUV mode overlay's input width has to be even and the - * algorithm above may adjust the width to be odd. - * - * Here we adjust the width if needed, preferring to increase - * the width if the original width was bigger. - */ - if ((w & 1) && - (oi->color_mode == OMAP_DSS_COLOR_YUV2 || - oi->color_mode == OMAP_DSS_COLOR_UYVY)) { - if (orig_w > w) - w += 1; - else - w -= 1; - } - } - - new_oi = *oi; - - /* update new_oi members which could have been possibly updated */ - new_oi.pos_x = x; - new_oi.pos_y = y; - new_oi.width = w; - new_oi.height = h; - new_oi.out_width = outw; - new_oi.out_height = outh; - new_oi.paddr = paddr; - - r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel, - c->replication, c->fifo_low, c->fifo_high); - if (r) { - /* this shouldn't happen */ - DSSERR("dispc_ovl_setup failed for ovl %d\n", plane); - dispc_ovl_enable(plane, 0); - return r; - } - - dispc_ovl_enable(plane, 1); - - return 0; -} - -static void configure_manager(enum omap_channel channel) -{ - struct omap_overlay_manager_info *mi; - - DSSDBGF("%d", channel); - - /* picking info from the cache */ - mi = &dss_cache.manager_cache[channel].info; - - dispc_mgr_set_default_color(channel, mi->default_color); - dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key); - dispc_mgr_enable_trans_key(channel, mi->trans_enabled); - dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled); - if (dss_has_feature(FEAT_CPR)) { - dispc_mgr_enable_cpr(channel, mi->cpr_enable); - dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs); - } -} - -/* configure_dispc() tries to write values from cache to shadow registers. - * It writes only to those managers/overlays that are not busy. - * returns 0 if everything could be written to shadow registers. - * returns 1 if not everything could be written to shadow registers. */ -static int configure_dispc(void) -{ - struct overlay_cache_data *oc; - struct manager_cache_data *mc; - const int num_ovls = dss_feat_get_num_ovls(); - const int num_mgrs = dss_feat_get_num_mgrs(); - int i; - int r; - bool mgr_busy[MAX_DSS_MANAGERS]; - bool mgr_go[MAX_DSS_MANAGERS]; - bool busy; - - r = 0; - busy = false; - - for (i = 0; i < num_mgrs; i++) { - mgr_busy[i] = dispc_mgr_go_busy(i); - mgr_go[i] = false; - } - - /* Commit overlay settings */ - for (i = 0; i < num_ovls; ++i) { - oc = &dss_cache.overlay_cache[i]; - mc = &dss_cache.manager_cache[oc->channel]; + mgr->set_device = &dss_mgr_set_device; + mgr->unset_device = &dss_mgr_unset_device; + mgr->apply = &omap_dss_mgr_apply; + mgr->set_manager_info = &dss_mgr_set_info; + mgr->get_manager_info = &dss_mgr_get_info; + mgr->wait_for_go = &dss_mgr_wait_for_go; + mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; - if (!oc->dirty) - continue; + mgr->caps = 0; + mgr->supported_displays = + dss_feat_get_supported_displays(mgr->id); - if (mc->manual_update && !mc->do_manual_update) - continue; + INIT_LIST_HEAD(&mgr->overlays); - if (mgr_busy[oc->channel]) { - busy = true; - continue; - } + r = kobject_init_and_add(&mgr->kobj, &manager_ktype, + &pdev->dev.kobj, "manager%d", i); - r = configure_overlay(i); if (r) - DSSERR("configure_overlay %d failed\n", i); - - oc->dirty = false; - oc->shadow_dirty = true; - mgr_go[oc->channel] = true; - } - - /* Commit manager settings */ - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - - if (!mc->dirty) - continue; - - if (mc->manual_update && !mc->do_manual_update) - continue; - - if (mgr_busy[i]) { - busy = true; - continue; - } - - configure_manager(i); - mc->dirty = false; - mc->shadow_dirty = true; - mgr_go[i] = true; - } - - /* set GO */ - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - - if (!mgr_go[i]) - continue; - - /* We don't need GO with manual update display. LCD iface will - * always be turned off after frame, and new settings will be - * taken in to use at next update */ - if (!mc->manual_update) - dispc_mgr_go(i); - } - - if (busy) - r = 1; - else - r = 0; - - return r; -} - -/* Make the coordinates even. There are some strange problems with OMAP and - * partial DSI update when the update widths are odd. */ -static void make_even(u16 *x, u16 *w) -{ - u16 x1, x2; - - x1 = *x; - x2 = *x + *w; - - x1 &= ~1; - x2 = ALIGN(x2, 2); - - *x = x1; - *w = x2 - x1; -} - -/* Configure dispc for partial update. Return possibly modified update - * area */ -void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) -{ - struct overlay_cache_data *oc; - struct manager_cache_data *mc; - struct omap_overlay_info *oi; - const int num_ovls = dss_feat_get_num_ovls(); - struct omap_overlay_manager *mgr; - int i; - u16 x, y, w, h; - unsigned long flags; - bool area_changed; - - x = *xi; - y = *yi; - w = *wi; - h = *hi; - - DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n", - *xi, *yi, *wi, *hi); - - mgr = dssdev->manager; - - if (!mgr) { - DSSDBG("no manager\n"); - return; + DSSERR("failed to create sysfs file\n"); } - make_even(&x, &w); - - spin_lock_irqsave(&dss_cache.lock, flags); - - /* - * Execute the outer loop until the inner loop has completed - * once without increasing the update area. This will ensure that - * all scaled overlays end up completely within the update area. - */ - do { - area_changed = false; - - /* We need to show the whole overlay if it is scaled. So look - * for those, and make the update area larger if found. - * Also mark the overlay cache dirty */ - for (i = 0; i < num_ovls; ++i) { - unsigned x1, y1, x2, y2; - unsigned outw, outh; - - oc = &dss_cache.overlay_cache[i]; - oi = &oc->info; - - if (oc->channel != mgr->id) - continue; - - oc->dirty = true; - - if (!enlarge_update_area) - continue; - - if (!oc->enabled) - continue; - - if (!dispc_is_overlay_scaled(oc)) - continue; - - outw = oi->out_width == 0 ? - oi->width : oi->out_width; - outh = oi->out_height == 0 ? - oi->height : oi->out_height; - - /* is the overlay outside the update region? */ - if (!rectangle_intersects(x, y, w, h, - oi->pos_x, oi->pos_y, - outw, outh)) - continue; - - /* if the overlay totally inside the update region? */ - if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh, - x, y, w, h)) - continue; - - if (x > oi->pos_x) - x1 = oi->pos_x; - else - x1 = x; - - if (y > oi->pos_y) - y1 = oi->pos_y; - else - y1 = y; - - if ((x + w) < (oi->pos_x + outw)) - x2 = oi->pos_x + outw; - else - x2 = x + w; - - if ((y + h) < (oi->pos_y + outh)) - y2 = oi->pos_y + outh; - else - y2 = y + h; - - x = x1; - y = y1; - w = x2 - x1; - h = y2 - y1; - - make_even(&x, &w); - - DSSDBG("changing upd area due to ovl(%d) " - "scaling %d,%d %dx%d\n", - i, x, y, w, h); - - area_changed = true; - } - } while (area_changed); - - mc = &dss_cache.manager_cache[mgr->id]; - mc->do_manual_update = true; - mc->enlarge_update_area = enlarge_update_area; - mc->x = x; - mc->y = y; - mc->w = w; - mc->h = h; - - configure_dispc(); - - mc->do_manual_update = false; - - spin_unlock_irqrestore(&dss_cache.lock, flags); - - *xi = x; - *yi = y; - *wi = w; - *hi = h; + return 0; } -void dss_start_update(struct omap_dss_device *dssdev) +void dss_uninit_overlay_managers(struct platform_device *pdev) { - struct manager_cache_data *mc; - struct overlay_cache_data *oc; - const int num_ovls = dss_feat_get_num_ovls(); - const int num_mgrs = dss_feat_get_num_mgrs(); - struct omap_overlay_manager *mgr; int i; - mgr = dssdev->manager; + for (i = 0; i < num_managers; ++i) { + struct omap_overlay_manager *mgr = &managers[i]; - for (i = 0; i < num_ovls; ++i) { - oc = &dss_cache.overlay_cache[i]; - if (oc->channel != mgr->id) - continue; - - oc->shadow_dirty = false; - } - - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - if (mgr->id != i) - continue; - - mc->shadow_dirty = false; + kobject_del(&mgr->kobj); + kobject_put(&mgr->kobj); } - dssdev->manager->enable(dssdev->manager); + kfree(managers); + managers = NULL; + num_managers = 0; } -static void dss_apply_irq_handler(void *data, u32 mask) +int omap_dss_get_num_overlay_managers(void) { - struct manager_cache_data *mc; - struct overlay_cache_data *oc; - const int num_ovls = dss_feat_get_num_ovls(); - const int num_mgrs = dss_feat_get_num_mgrs(); - int i, r; - bool mgr_busy[MAX_DSS_MANAGERS]; - u32 irq_mask; - - for (i = 0; i < num_mgrs; i++) - mgr_busy[i] = dispc_mgr_go_busy(i); - - spin_lock(&dss_cache.lock); - - for (i = 0; i < num_ovls; ++i) { - oc = &dss_cache.overlay_cache[i]; - if (!mgr_busy[oc->channel]) - oc->shadow_dirty = false; - } - - for (i = 0; i < num_mgrs; ++i) { - mc = &dss_cache.manager_cache[i]; - if (!mgr_busy[i]) - mc->shadow_dirty = false; - } - - r = configure_dispc(); - if (r == 1) - goto end; - - /* re-read busy flags */ - for (i = 0; i < num_mgrs; i++) - mgr_busy[i] = dispc_mgr_go_busy(i); - - /* keep running as long as there are busy managers, so that - * we can collect overlay-applied information */ - for (i = 0; i < num_mgrs; ++i) { - if (mgr_busy[i]) - goto end; - } - - irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN; - if (dss_has_feature(FEAT_MGR_LCD2)) - irq_mask |= DISPC_IRQ_VSYNC2; - - omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); - dss_cache.irq_enabled = false; - -end: - spin_unlock(&dss_cache.lock); + return num_managers; } +EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); -static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) { - struct overlay_cache_data *oc; - struct manager_cache_data *mc; - int i; - struct omap_overlay *ovl; - int num_planes_enabled = 0; - bool use_fifomerge; - unsigned long flags; - int r; - - DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); - - r = dispc_runtime_get(); - if (r) - return r; - - spin_lock_irqsave(&dss_cache.lock, flags); - - /* Configure overlays */ - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_dss_device *dssdev; - - ovl = omap_dss_get_overlay(i); - - oc = &dss_cache.overlay_cache[ovl->id]; - - if (ovl->manager_changed) { - ovl->manager_changed = false; - ovl->info_dirty = true; - } - - if (!overlay_enabled(ovl)) { - if (oc->enabled) { - oc->enabled = false; - oc->dirty = true; - } - continue; - } - - if (!ovl->info_dirty) { - if (oc->enabled) - ++num_planes_enabled; - continue; - } - - dssdev = ovl->manager->device; - - if (dss_check_overlay(ovl, dssdev)) { - if (oc->enabled) { - oc->enabled = false; - oc->dirty = true; - } - continue; - } - - ovl->info_dirty = false; - oc->dirty = true; - oc->info = ovl->info; - - oc->replication = - dss_use_replication(dssdev, ovl->info.color_mode); - - oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC; - - oc->channel = ovl->manager->id; - - oc->enabled = true; - - ++num_planes_enabled; - } - - /* Configure managers */ - list_for_each_entry(mgr, &manager_list, list) { - struct omap_dss_device *dssdev; + if (num >= num_managers) + return NULL; - mc = &dss_cache.manager_cache[mgr->id]; - - if (mgr->device_changed) { - mgr->device_changed = false; - mgr->info_dirty = true; - } - - if (!mgr->info_dirty) - continue; - - if (!mgr->device) - continue; - - dssdev = mgr->device; - - mgr->info_dirty = false; - mc->dirty = true; - mc->info = mgr->info; - - mc->manual_update = - dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; - } - - /* XXX TODO: Try to get fifomerge working. The problem is that it - * affects both managers, not individually but at the same time. This - * means the change has to be well synchronized. I guess the proper way - * is to have a two step process for fifo merge: - * fifomerge enable: - * 1. disable other planes, leaving one plane enabled - * 2. wait until the planes are disabled on HW - * 3. config merged fifo thresholds, enable fifomerge - * fifomerge disable: - * 1. config unmerged fifo thresholds, disable fifomerge - * 2. wait until fifo changes are in HW - * 3. enable planes - */ - use_fifomerge = false; - - /* Configure overlay fifos */ - for (i = 0; i < omap_dss_get_num_overlays(); ++i) { - struct omap_dss_device *dssdev; - u32 size, burst_size; - - ovl = omap_dss_get_overlay(i); - - oc = &dss_cache.overlay_cache[ovl->id]; - - if (!oc->enabled) - continue; - - dssdev = ovl->manager->device; - - size = dispc_ovl_get_fifo_size(ovl->id); - if (use_fifomerge) - size *= 3; - - burst_size = dispc_ovl_get_burst_size(ovl->id); - - switch (dssdev->type) { - case OMAP_DISPLAY_TYPE_DPI: - case OMAP_DISPLAY_TYPE_DBI: - case OMAP_DISPLAY_TYPE_SDI: - case OMAP_DISPLAY_TYPE_VENC: - case OMAP_DISPLAY_TYPE_HDMI: - default_get_overlay_fifo_thresholds(ovl->id, size, - burst_size, &oc->fifo_low, - &oc->fifo_high); - break; -#ifdef CONFIG_OMAP2_DSS_DSI - case OMAP_DISPLAY_TYPE_DSI: - dsi_get_overlay_fifo_thresholds(ovl->id, size, - burst_size, &oc->fifo_low, - &oc->fifo_high); - break; -#endif - default: - BUG(); - } - } - - r = 0; - if (!dss_cache.irq_enabled) { - u32 mask; - - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN; - if (dss_has_feature(FEAT_MGR_LCD2)) - mask |= DISPC_IRQ_VSYNC2; - - r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); - dss_cache.irq_enabled = true; - } - configure_dispc(); - - spin_unlock_irqrestore(&dss_cache.lock, flags); - - dispc_runtime_put(); - - return r; + return &managers[num]; } +EXPORT_SYMBOL(omap_dss_get_overlay_manager); -static int dss_check_manager(struct omap_overlay_manager *mgr) +int dss_mgr_simple_check(struct omap_overlay_manager *mgr, + const struct omap_overlay_manager_info *info) { if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { /* * OMAP3 supports only graphics source transparency color key * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 - * Alpha Mode + * Alpha Mode. */ - if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled - && mgr->info.trans_key_type != - OMAP_DSS_COLOR_KEY_GFX_DST) + if (info->partial_alpha_enabled && info->trans_enabled + && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { + DSSERR("check_manager: illegal transparency key\n"); return -EINVAL; + } } return 0; } -static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info) -{ - int r; - struct omap_overlay_manager_info old_info; - - old_info = mgr->info; - mgr->info = *info; - - r = dss_check_manager(mgr); - if (r) { - mgr->info = old_info; - return r; - } - - mgr->info_dirty = true; - - return 0; -} - -static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, - struct omap_overlay_manager_info *info) +static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, + struct omap_overlay_info **overlay_infos) { - *info = mgr->info; -} + struct omap_overlay *ovl1, *ovl2; + struct omap_overlay_info *info1, *info2; -static int dss_mgr_enable(struct omap_overlay_manager *mgr) -{ - dispc_mgr_enable(mgr->id, 1); - return 0; -} + list_for_each_entry(ovl1, &mgr->overlays, list) { + info1 = overlay_infos[ovl1->id]; -static int dss_mgr_disable(struct omap_overlay_manager *mgr) -{ - dispc_mgr_enable(mgr->id, 0); - return 0; -} - -static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) -{ - ++num_managers; - list_add_tail(&manager->list, &manager_list); -} - -int dss_init_overlay_managers(struct platform_device *pdev) -{ - int i, r; - - spin_lock_init(&dss_cache.lock); - - INIT_LIST_HEAD(&manager_list); - - num_managers = 0; - - for (i = 0; i < dss_feat_get_num_mgrs(); ++i) { - struct omap_overlay_manager *mgr; - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); - - BUG_ON(mgr == NULL); - - switch (i) { - case 0: - mgr->name = "lcd"; - mgr->id = OMAP_DSS_CHANNEL_LCD; - break; - case 1: - mgr->name = "tv"; - mgr->id = OMAP_DSS_CHANNEL_DIGIT; - break; - case 2: - mgr->name = "lcd2"; - mgr->id = OMAP_DSS_CHANNEL_LCD2; - break; - } - - mgr->set_device = &omap_dss_set_device; - mgr->unset_device = &omap_dss_unset_device; - mgr->apply = &omap_dss_mgr_apply; - mgr->set_manager_info = &omap_dss_mgr_set_info; - mgr->get_manager_info = &omap_dss_mgr_get_info; - mgr->wait_for_go = &dss_mgr_wait_for_go; - mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; - - mgr->enable = &dss_mgr_enable; - mgr->disable = &dss_mgr_disable; - - mgr->caps = 0; - mgr->supported_displays = - dss_feat_get_supported_displays(mgr->id); + if (info1 == NULL) + continue; - dss_overlay_setup_dispc_manager(mgr); + list_for_each_entry(ovl2, &mgr->overlays, list) { + if (ovl1 == ovl2) + continue; - omap_dss_add_overlay_manager(mgr); + info2 = overlay_infos[ovl2->id]; - r = kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "manager%d", i); + if (info2 == NULL) + continue; - if (r) { - DSSERR("failed to create sysfs file\n"); - continue; + if (info1->zorder == info2->zorder) { + DSSERR("overlays %d and %d have the same " + "zorder %d\n", + ovl1->id, ovl2->id, info1->zorder); + return -EINVAL; + } } } return 0; } -void dss_uninit_overlay_managers(struct platform_device *pdev) +int dss_mgr_check(struct omap_overlay_manager *mgr, + struct omap_dss_device *dssdev, + struct omap_overlay_manager_info *info, + struct omap_overlay_info **overlay_infos) { - struct omap_overlay_manager *mgr; + struct omap_overlay *ovl; + int r; - while (!list_empty(&manager_list)) { - mgr = list_first_entry(&manager_list, - struct omap_overlay_manager, list); - list_del(&mgr->list); - kobject_del(&mgr->kobj); - kobject_put(&mgr->kobj); - kfree(mgr); + if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { + r = dss_mgr_check_zorder(mgr, overlay_infos); + if (r) + return r; } - num_managers = 0; -} + list_for_each_entry(ovl, &mgr->overlays, list) { + struct omap_overlay_info *oi; + int r; -int omap_dss_get_num_overlay_managers(void) -{ - return num_managers; -} -EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); + oi = overlay_infos[ovl->id]; -struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) -{ - int i = 0; - struct omap_overlay_manager *mgr; + if (oi == NULL) + continue; - list_for_each_entry(mgr, &manager_list, list) { - if (i++ == num) - return mgr; + r = dss_ovl_check(ovl, oi, dssdev); + if (r) + return r; } - return NULL; + return 0; } -EXPORT_SYMBOL(omap_dss_get_overlay_manager); - diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index ab8e40e48759..6e821810deec 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -38,7 +38,7 @@ #include "dss_features.h" static int num_overlays; -static struct list_head overlay_list; +static struct omap_overlay *overlays; static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) { @@ -124,19 +124,31 @@ err: static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + return snprintf(buf, PAGE_SIZE, "%d,%d\n", - ovl->info.width, ovl->info.height); + info.width, info.height); } static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); } static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + return snprintf(buf, PAGE_SIZE, "%d,%d\n", - ovl->info.pos_x, ovl->info.pos_y); + info.pos_x, info.pos_y); } static ssize_t overlay_position_store(struct omap_overlay *ovl, @@ -170,8 +182,12 @@ static ssize_t overlay_position_store(struct omap_overlay *ovl, static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + return snprintf(buf, PAGE_SIZE, "%d,%d\n", - ovl->info.out_width, ovl->info.out_height); + info.out_width, info.out_height); } static ssize_t overlay_output_size_store(struct omap_overlay *ovl, @@ -205,7 +221,7 @@ static ssize_t overlay_output_size_store(struct omap_overlay *ovl, static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); } static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, @@ -213,33 +229,30 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, { int r; bool enable; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); r = strtobool(buf, &enable); if (r) return r; - info.enabled = enable; + if (enable) + r = ovl->enable(ovl); + else + r = ovl->disable(ovl); - r = ovl->set_overlay_info(ovl, &info); if (r) return r; - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - return size; } static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + return snprintf(buf, PAGE_SIZE, "%d\n", - ovl->info.global_alpha); + info.global_alpha); } static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, @@ -276,8 +289,12 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, char *buf) { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + return snprintf(buf, PAGE_SIZE, "%d\n", - ovl->info.pre_mult_alpha); + info.pre_mult_alpha); } static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, @@ -313,7 +330,11 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder); + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); } static ssize_t overlay_zorder_store(struct omap_overlay *ovl, @@ -430,183 +451,6 @@ static struct kobj_type overlay_ktype = { .default_attrs = overlay_sysfs_attrs, }; -/* Check if overlay parameters are compatible with display */ -int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) -{ - struct omap_overlay_info *info; - u16 outw, outh; - u16 dw, dh; - int i; - - if (!dssdev) - return 0; - - if (!ovl->info.enabled) - return 0; - - info = &ovl->info; - - if (info->paddr == 0) { - DSSDBG("check_overlay failed: paddr 0\n"); - return -EINVAL; - } - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", - ovl->id, - info->pos_x, info->pos_y, - info->width, info->height, - info->out_width, info->out_height, - dw, dh); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { - outw = info->width; - outh = info->height; - } else { - if (info->out_width == 0) - outw = info->width; - else - outw = info->out_width; - - if (info->out_height == 0) - outh = info->height; - else - outh = info->out_height; - } - - if (dw < info->pos_x + outw) { - DSSDBG("check_overlay failed 1: %d < %d + %d\n", - dw, info->pos_x, outw); - return -EINVAL; - } - - if (dh < info->pos_y + outh) { - DSSDBG("check_overlay failed 2: %d < %d + %d\n", - dh, info->pos_y, outh); - return -EINVAL; - } - - if ((ovl->supported_modes & info->color_mode) == 0) { - DSSERR("overlay doesn't support mode %d\n", info->color_mode); - return -EINVAL; - } - - if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) { - if (info->zorder < 0 || info->zorder > 3) { - DSSERR("zorder out of range: %d\n", - info->zorder); - return -EINVAL; - } - /* - * Check that zorder doesn't match with zorder of any other - * overlay which is enabled and is also connected to the same - * manager - */ - for (i = 0; i < omap_dss_get_num_overlays(); i++) { - struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i); - - if (tmp_ovl->id != ovl->id && - tmp_ovl->manager == ovl->manager && - tmp_ovl->info.enabled == true && - tmp_ovl->info.zorder == info->zorder) { - DSSERR("%s and %s have same zorder: %d\n", - ovl->name, tmp_ovl->name, info->zorder); - return -EINVAL; - } - } - } - - return 0; -} - -static int dss_ovl_set_overlay_info(struct omap_overlay *ovl, - struct omap_overlay_info *info) -{ - int r; - struct omap_overlay_info old_info; - - old_info = ovl->info; - ovl->info = *info; - - if (ovl->manager) { - r = dss_check_overlay(ovl, ovl->manager->device); - if (r) { - ovl->info = old_info; - return r; - } - } - - ovl->info_dirty = true; - - return 0; -} - -static void dss_ovl_get_overlay_info(struct omap_overlay *ovl, - struct omap_overlay_info *info) -{ - *info = ovl->info; -} - -static int dss_ovl_wait_for_go(struct omap_overlay *ovl) -{ - return dss_mgr_wait_for_go_ovl(ovl); -} - -static int omap_dss_set_manager(struct omap_overlay *ovl, - struct omap_overlay_manager *mgr) -{ - if (!mgr) - return -EINVAL; - - if (ovl->manager) { - DSSERR("overlay '%s' already has a manager '%s'\n", - ovl->name, ovl->manager->name); - return -EINVAL; - } - - if (ovl->info.enabled) { - DSSERR("overlay has to be disabled to change the manager\n"); - return -EINVAL; - } - - ovl->manager = mgr; - ovl->manager_changed = true; - - /* XXX: When there is an overlay on a DSI manual update display, and - * the overlay is first disabled, then moved to tv, and enabled, we - * seem to get SYNC_LOST_DIGIT error. - * - * Waiting doesn't seem to help, but updating the manual update display - * after disabling the overlay seems to fix this. This hints that the - * overlay is perhaps somehow tied to the LCD output until the output - * is updated. - * - * Userspace workaround for this is to update the LCD after disabling - * the overlay, but before moving the overlay to TV. - */ - - return 0; -} - -static int omap_dss_unset_manager(struct omap_overlay *ovl) -{ - if (!ovl->manager) { - DSSERR("failed to detach overlay: manager not set\n"); - return -EINVAL; - } - - if (ovl->info.enabled) { - DSSERR("overlay has to be disabled to unset the manager\n"); - return -EINVAL; - } - - ovl->manager = NULL; - ovl->manager_changed = true; - - return 0; -} - int omap_dss_get_num_overlays(void) { return num_overlays; @@ -615,134 +459,65 @@ EXPORT_SYMBOL(omap_dss_get_num_overlays); struct omap_overlay *omap_dss_get_overlay(int num) { - int i = 0; - struct omap_overlay *ovl; + if (num >= num_overlays) + return NULL; - list_for_each_entry(ovl, &overlay_list, list) { - if (i++ == num) - return ovl; - } - - return NULL; + return &overlays[num]; } EXPORT_SYMBOL(omap_dss_get_overlay); -static void omap_dss_add_overlay(struct omap_overlay *overlay) -{ - ++num_overlays; - list_add_tail(&overlay->list, &overlay_list); -} - -static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS]; - -void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) -{ - mgr->num_overlays = dss_feat_get_num_ovls(); - mgr->overlays = dispc_overlays; -} - -#ifdef L4_EXAMPLE -static struct omap_overlay *l4_overlays[1]; -void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr) -{ - mgr->num_overlays = 1; - mgr->overlays = l4_overlays; -} -#endif - void dss_init_overlays(struct platform_device *pdev) { int i, r; - INIT_LIST_HEAD(&overlay_list); + num_overlays = dss_feat_get_num_ovls(); - num_overlays = 0; + overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, + GFP_KERNEL); - for (i = 0; i < dss_feat_get_num_ovls(); ++i) { - struct omap_overlay *ovl; - ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); + BUG_ON(overlays == NULL); - BUG_ON(ovl == NULL); + for (i = 0; i < num_overlays; ++i) { + struct omap_overlay *ovl = &overlays[i]; switch (i) { case 0: ovl->name = "gfx"; ovl->id = OMAP_DSS_GFX; - ovl->info.global_alpha = 255; - ovl->info.zorder = 0; break; case 1: ovl->name = "vid1"; ovl->id = OMAP_DSS_VIDEO1; - ovl->info.global_alpha = 255; - ovl->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; break; case 2: ovl->name = "vid2"; ovl->id = OMAP_DSS_VIDEO2; - ovl->info.global_alpha = 255; - ovl->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; break; case 3: ovl->name = "vid3"; ovl->id = OMAP_DSS_VIDEO3; - ovl->info.global_alpha = 255; - ovl->info.zorder = - dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; break; } - ovl->set_manager = &omap_dss_set_manager; - ovl->unset_manager = &omap_dss_unset_manager; - ovl->set_overlay_info = &dss_ovl_set_overlay_info; - ovl->get_overlay_info = &dss_ovl_get_overlay_info; - ovl->wait_for_go = &dss_ovl_wait_for_go; + ovl->is_enabled = &dss_ovl_is_enabled; + ovl->enable = &dss_ovl_enable; + ovl->disable = &dss_ovl_disable; + ovl->set_manager = &dss_ovl_set_manager; + ovl->unset_manager = &dss_ovl_unset_manager; + ovl->set_overlay_info = &dss_ovl_set_info; + ovl->get_overlay_info = &dss_ovl_get_info; + ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); - omap_dss_add_overlay(ovl); - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, &pdev->dev.kobj, "overlay%d", i); - if (r) { - DSSERR("failed to create sysfs file\n"); - continue; - } - - dispc_overlays[i] = ovl; - } - -#ifdef L4_EXAMPLE - { - struct omap_overlay *ovl; - ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); - - BUG_ON(ovl == NULL); - - ovl->name = "l4"; - ovl->supported_modes = OMAP_DSS_COLOR_RGB24U; - - ovl->set_manager = &omap_dss_set_manager; - ovl->unset_manager = &omap_dss_unset_manager; - ovl->set_overlay_info = &dss_ovl_set_overlay_info; - ovl->get_overlay_info = &dss_ovl_get_overlay_info; - - omap_dss_add_overlay(ovl); - - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, - &pdev->dev.kobj, "overlayl4"); - if (r) DSSERR("failed to create sysfs file\n"); - - l4_overlays[0] = ovl; } -#endif } /* connect overlays to the new device, if not already connected. if force @@ -795,8 +570,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) ovl = omap_dss_get_overlay(i); if (!ovl->manager || force) { if (ovl->manager) - omap_dss_unset_manager(ovl); - omap_dss_set_manager(ovl, mgr); + ovl->unset_manager(ovl); + ovl->set_manager(ovl, mgr); } } @@ -806,17 +581,95 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) void dss_uninit_overlays(struct platform_device *pdev) { - struct omap_overlay *ovl; + int i; + + for (i = 0; i < num_overlays; ++i) { + struct omap_overlay *ovl = &overlays[i]; - while (!list_empty(&overlay_list)) { - ovl = list_first_entry(&overlay_list, - struct omap_overlay, list); - list_del(&ovl->list); kobject_del(&ovl->kobj); kobject_put(&ovl->kobj); - kfree(ovl); } + kfree(overlays); + overlays = NULL; num_overlays = 0; } +int dss_ovl_simple_check(struct omap_overlay *ovl, + const struct omap_overlay_info *info) +{ + if (info->paddr == 0) { + DSSERR("check_overlay: paddr cannot be 0\n"); + return -EINVAL; + } + + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { + if (info->out_width != 0 && info->width != info->out_width) { + DSSERR("check_overlay: overlay %d doesn't support " + "scaling\n", ovl->id); + return -EINVAL; + } + + if (info->out_height != 0 && info->height != info->out_height) { + DSSERR("check_overlay: overlay %d doesn't support " + "scaling\n", ovl->id); + return -EINVAL; + } + } + + if ((ovl->supported_modes & info->color_mode) == 0) { + DSSERR("check_overlay: overlay %d doesn't support mode %d\n", + ovl->id, info->color_mode); + return -EINVAL; + } + + if (info->zorder >= omap_dss_get_num_overlays()) { + DSSERR("check_overlay: zorder %d too high\n", info->zorder); + return -EINVAL; + } + + return 0; +} + +int dss_ovl_check(struct omap_overlay *ovl, + struct omap_overlay_info *info, struct omap_dss_device *dssdev) +{ + u16 outw, outh; + u16 dw, dh; + + if (dssdev == NULL) + return 0; + + dssdev->driver->get_resolution(dssdev, &dw, &dh); + + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { + outw = info->width; + outh = info->height; + } else { + if (info->out_width == 0) + outw = info->width; + else + outw = info->out_width; + + if (info->out_height == 0) + outh = info->height; + else + outh = info->out_height; + } + + if (dw < info->pos_x + outw) { + DSSERR("overlay %d horizontally not inside the display area " + "(%d + %d >= %d)\n", + ovl->id, info->pos_x, outw, dw); + return -EINVAL; + } + + if (dh < info->pos_y + outh) { + DSSERR("overlay %d vertically not inside the display area " + "(%d + %d >= %d)\n", + ovl->id, info->pos_y, outh, dh); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1130c608a561..814bb9500dca 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -784,7 +784,6 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, if (*w == 0 || *h == 0) return -EINVAL; - dss_setup_partial_planes(dssdev, x, y, w, h, true); dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); return 0; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 40305ad7841e..8266ca0d666b 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -123,10 +123,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err_sdi_enable; mdelay(2); - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err_mgr_enable; return 0; +err_mgr_enable: + dss_sdi_disable(); err_sdi_enable: err_set_dispc_clock_div: err_set_dss_clock_div: @@ -145,7 +149,7 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); dss_sdi_disable(); diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 2c3443dabb14..7503f7f619a7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h @@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops { void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) + void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); +#endif + }; struct hdmi_ip_data { @@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); - +#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ + defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) +void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); +#endif #endif diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e1a6ce518af6..9af81f18f163 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c @@ -1204,36 +1204,13 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, return 0; } -int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, - struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) +void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) { - int err = 0; - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - REG_FLD_MOD(hdmi_av_base(ip_data), - HDMI_CORE_AV_AUD_MODE, 1, 0, 0); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 1, 31, 31); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 1, 30, 30); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - REG_FLD_MOD(hdmi_av_base(ip_data), - HDMI_CORE_AV_AUD_MODE, 0, 0, 0); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 0, 30, 30); - REG_FLD_MOD(hdmi_wp_base(ip_data), - HDMI_WP_AUDIO_CTRL, 0, 31, 31); - break; - default: - err = -EINVAL; - } - return err; + REG_FLD_MOD(hdmi_av_base(ip_data), + HDMI_CORE_AV_AUD_MODE, enable, 0, 0); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, enable, 31, 31); + REG_FLD_MOD(hdmi_wp_base(ip_data), + HDMI_WP_AUDIO_CTRL, enable, 30, 30); } #endif diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 204095632d27..a442998980f1 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h @@ -576,9 +576,6 @@ struct hdmi_core_audio_config { #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) -int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, - struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai); int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, u32 sample_freq, u32 *n, u32 *cts); void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 7533458ba4d2..b3e9f9091581 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -417,9 +417,10 @@ static const struct venc_config *venc_timings_to_config( BUG(); } -static void venc_power_on(struct omap_dss_device *dssdev) +static int venc_power_on(struct omap_dss_device *dssdev) { u32 l; + int r; venc_reset(); venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); @@ -447,7 +448,22 @@ static void venc_power_on(struct omap_dss_device *dssdev) if (dssdev->platform_enable) dssdev->platform_enable(dssdev); - dssdev->manager->enable(dssdev->manager); + r = dss_mgr_enable(dssdev->manager); + if (r) + goto err; + + return 0; + +err: + venc_write_reg(VENC_OUTPUT_CONTROL, 0); + dss_set_dac_pwrdn_bgz(0); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + + regulator_disable(venc.vdda_dac_reg); + + return r; } static void venc_power_off(struct omap_dss_device *dssdev) @@ -455,7 +471,7 @@ static void venc_power_off(struct omap_dss_device *dssdev) venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dssdev->manager->disable(dssdev->manager); + dss_mgr_disable(dssdev->manager); if (dssdev->platform_disable) dssdev->platform_disable(dssdev); @@ -504,7 +520,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) if (r) goto err1; - venc_power_on(dssdev); + r = venc_power_on(dssdev); + if (r) + goto err2; venc.wss_data = 0; @@ -512,6 +530,8 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) mutex_unlock(&venc.venc_lock); return 0; +err2: + venc_runtime_put(); err1: omap_dss_stop_device(dssdev); err0: diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index df7bcce5b107..16ba6196f330 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -111,28 +111,22 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) set_fb_fix(fbi); } - if (pi->enabled) { - struct omap_overlay_info info; + if (!pi->enabled) { + r = ovl->disable(ovl); + if (r) + goto undo; + } + if (pi->enabled) { r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, pi->out_width, pi->out_height); if (r) goto undo; - - ovl->get_overlay_info(ovl, &info); - - if (!info.enabled) { - info.enabled = pi->enabled; - r = ovl->set_overlay_info(ovl, &info); - if (r) - goto undo; - } } else { struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); - info.enabled = pi->enabled; info.pos_x = pi->pos_x; info.pos_y = pi->pos_y; info.out_width = pi->out_width; @@ -146,6 +140,12 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ovl->manager) ovl->manager->apply(ovl->manager); + if (pi->enabled) { + r = ovl->enable(ovl); + if (r) + goto undo; + } + /* Release the locks in a specific order to keep lockdep happy */ if (old_rg->id > new_rg->id) { omapfb_put_mem_region(old_rg); @@ -189,19 +189,19 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) memset(pi, 0, sizeof(*pi)); } else { struct omap_overlay *ovl; - struct omap_overlay_info *ovli; + struct omap_overlay_info ovli; ovl = ofbi->overlays[0]; - ovli = &ovl->info; + ovl->get_overlay_info(ovl, &ovli); - pi->pos_x = ovli->pos_x; - pi->pos_y = ovli->pos_y; - pi->enabled = ovli->enabled; + pi->pos_x = ovli.pos_x; + pi->pos_y = ovli.pos_y; + pi->enabled = ovl->is_enabled(ovl); pi->channel_out = 0; /* xxx */ pi->mirror = 0; pi->mem_idx = get_mem_idx(ofbi); - pi->out_width = ovli->out_width; - pi->out_height = ovli->out_height; + pi->out_width = ovli.out_width; + pi->out_height = ovli.out_height; } return 0; @@ -238,7 +238,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) continue; for (j = 0; j < ofbi2->num_overlays; j++) { - if (ofbi2->overlays[j]->info.enabled) { + struct omap_overlay *ovl; + ovl = ofbi2->overlays[j]; + if (ovl->is_enabled(ovl)) { r = -EBUSY; goto out; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 70aa47de7146..ce158311ff59 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -43,18 +43,18 @@ static char *def_mode; static char *def_vram; -static int def_vrfb; +static bool def_vrfb; static int def_rotate; -static int def_mirror; +static bool def_mirror; static bool auto_update; static unsigned int auto_update_freq; module_param(auto_update, bool, 0); module_param(auto_update_freq, uint, 0644); #ifdef DEBUG -unsigned int omapfb_debug; +bool omapfb_debug; module_param_named(debug, omapfb_debug, bool, 0644); -static unsigned int omapfb_test_pattern; +static bool omapfb_test_pattern; module_param_named(test, omapfb_test_pattern, bool, 0644); #endif @@ -970,16 +970,20 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) outh = var->yres; } } else { - outw = ovl->info.out_width; - outh = ovl->info.out_height; + struct omap_overlay_info info; + ovl->get_overlay_info(ovl, &info); + outw = info.out_width; + outh = info.out_height; } if (init) { posx = 0; posy = 0; } else { - posx = ovl->info.pos_x; - posy = ovl->info.pos_y; + struct omap_overlay_info info; + ovl->get_overlay_info(ovl, &info); + posx = info.pos_x; + posy = info.pos_y; } r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); @@ -2067,6 +2071,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) if (ofbi->num_overlays > 0) { struct omap_overlay *ovl = ofbi->overlays[0]; + ovl->manager->apply(ovl->manager); + r = omapfb_overlay_enable(ovl, 1); if (r) { diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 1694d5148f32..e8d8cc76a435 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -473,7 +473,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, continue; for (j = 0; j < ofbi2->num_overlays; j++) { - if (ofbi2->overlays[j]->info.enabled) { + struct omap_overlay *ovl; + ovl = ofbi2->overlays[j]; + if (ovl->is_enabled(ovl)) { r = -EBUSY; goto out; } diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index fdf0edeccf4e..c0bdc9b54ecf 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -32,7 +32,7 @@ #include <video/omapdss.h> #ifdef DEBUG -extern unsigned int omapfb_debug; +extern bool omapfb_debug; #define DBG(format, ...) \ do { \ if (omapfb_debug) \ @@ -181,13 +181,10 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev) static inline int omapfb_overlay_enable(struct omap_overlay *ovl, int enable) { - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - if (info.enabled == enable) - return 0; - info.enabled = enable; - return ovl->set_overlay_info(ovl, &info); + if (enable) + return ovl->enable(ovl); + else + return ovl->disable(ovl); } static inline struct omapfb2_mem_region * diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index dc7bfa91e57a..df31a24a5026 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -78,12 +78,12 @@ static char *mode_option __devinitdata; * these flags allow the user to specify that requests for +ve sync * should be silently turned in -ve sync. */ -static int lowhsync; -static int lowvsync; -static int noaccel __devinitdata; +static bool lowhsync; +static bool lowvsync; +static bool noaccel __devinitdata; /* mtrr option */ #ifdef CONFIG_MTRR -static int nomtrr __devinitdata; +static bool nomtrr __devinitdata; #endif /* diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 6632ee5ecb7e..055e527a8e45 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -57,11 +57,11 @@ */ static int hwcursor = 1; static char *mode_option __devinitdata; -static int noaccel __devinitdata; +static bool noaccel __devinitdata; /* mtrr option */ #ifdef CONFIG_MTRR -static int nomtrr __devinitdata; +static bool nomtrr __devinitdata; #endif /* diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c index b2252fea2858..6d30428e9cf9 100644 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ b/drivers/video/pnx4008/pnxrgbfb.c @@ -193,17 +193,6 @@ static struct platform_driver rgbfb_driver = { .remove = rgbfb_remove, }; -static int __init rgbfb_init(void) -{ - return platform_driver_register(&rgbfb_driver); -} - -static void __exit rgbfb_exit(void) -{ - platform_driver_unregister(&rgbfb_driver); -} - -module_init(rgbfb_init); -module_exit(rgbfb_exit); +module_platform_driver(rgbfb_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c index 50e00395240f..c5c741452cac 100644 --- a/drivers/video/pnx4008/sdum.c +++ b/drivers/video/pnx4008/sdum.c @@ -856,17 +856,6 @@ static struct platform_driver sdum_driver = { .resume = sdum_resume, }; -int __init sdum_init(void) -{ - return platform_driver_register(&sdum_driver); -} - -static void __exit sdum_exit(void) -{ - platform_driver_unregister(&sdum_driver); -}; - -module_init(sdum_init); -module_exit(sdum_exit); +module_platform_driver(sdum_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index 18ead6f0184d..8384b941f6ba 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -832,17 +832,7 @@ static struct platform_driver pxa168fb_driver = { .remove = __devexit_p(pxa168fb_remove), }; -static int __init pxa168fb_init(void) -{ - return platform_driver_register(&pxa168fb_driver); -} -module_init(pxa168fb_init); - -static void __exit pxa168fb_exit(void) -{ - platform_driver_unregister(&pxa168fb_driver); -} -module_exit(pxa168fb_exit); +module_platform_driver(pxa168fb_driver); MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> " "Green Wan <gwan@marvell.com>"); diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 1ed8b366618d..1d71c08a818f 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -747,20 +747,7 @@ static struct platform_driver pxa3xx_gcu_driver = { }, }; -static int __init -pxa3xx_gcu_init(void) -{ - return platform_driver_register(&pxa3xx_gcu_driver); -} - -static void __exit -pxa3xx_gcu_exit(void) -{ - platform_driver_unregister(&pxa3xx_gcu_driver); -} - -module_init(pxa3xx_gcu_init); -module_exit(pxa3xx_gcu_exit); +module_platform_driver(pxa3xx_gcu_driver); MODULE_DESCRIPTION("PXA3xx graphics controller unit driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index d8ab7be4fd6b..2f58cf9c813b 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -207,9 +207,9 @@ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); /* command line data, set in rivafb_setup() */ static int flatpanel __devinitdata = -1; /* Autodetect later */ static int forceCRTC __devinitdata = -1; -static int noaccel __devinitdata = 0; +static bool noaccel __devinitdata = 0; #ifdef CONFIG_MTRR -static int nomtrr __devinitdata = 0; +static bool nomtrr __devinitdata = 0; #endif #ifdef CONFIG_PMAC_BACKLIGHT static int backlight __devinitdata = 1; @@ -218,7 +218,7 @@ static int backlight __devinitdata = 0; #endif static char *mode_option __devinitdata = NULL; -static int strictmode = 0; +static bool strictmode = 0; static struct fb_fix_screeninfo __devinitdata rivafb_fix = { .type = FB_TYPE_PACKED_PIXELS, diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0753b1cfcb8b..0c63b69b6340 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -192,6 +192,7 @@ struct s3c_fb_vsync { * @regs: The mapped hardware registers. * @variant: Variant information for this hardware. * @enabled: A bitmask of enabled hardware windows. + * @output_on: Flag if the physical output is enabled. * @pdata: The platform configuration data passed with the device. * @windows: The hardware windows that have been claimed. * @irq_no: IRQ line number @@ -208,6 +209,7 @@ struct s3c_fb { struct s3c_fb_variant variant; unsigned char enabled; + bool output_on; struct s3c_fb_platdata *pdata; struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; @@ -441,6 +443,39 @@ static void shadow_protect_win(struct s3c_fb_win *win, bool protect) } /** + * s3c_fb_enable() - Set the state of the main LCD output + * @sfb: The main framebuffer state. + * @enable: The state to set. + */ +static void s3c_fb_enable(struct s3c_fb *sfb, int enable) +{ + u32 vidcon0 = readl(sfb->regs + VIDCON0); + + if (enable && !sfb->output_on) + pm_runtime_get_sync(sfb->dev); + + if (enable) { + vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; + } else { + /* see the note in the framebuffer datasheet about + * why you cannot take both of these bits down at the + * same time. */ + + if (vidcon0 & VIDCON0_ENVID) { + vidcon0 |= VIDCON0_ENVID; + vidcon0 &= ~VIDCON0_ENVID_F; + } + } + + writel(vidcon0, sfb->regs + VIDCON0); + + if (!enable && sfb->output_on) + pm_runtime_put_sync(sfb->dev); + + sfb->output_on = enable; +} + +/** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * @@ -461,6 +496,8 @@ static int s3c_fb_set_par(struct fb_info *info) dev_dbg(sfb->dev, "setting framebuffer parameters\n"); + pm_runtime_get_sync(sfb->dev); + shadow_protect_win(win, 1); switch (var->bits_per_pixel) { @@ -510,9 +547,10 @@ static int s3c_fb_set_par(struct fb_info *info) if (sfb->variant.is_2443) data |= (1 << 5); - data |= VIDCON0_ENVID | VIDCON0_ENVID_F; writel(data, regs + VIDCON0); + s3c_fb_enable(sfb, 1); + data = VIDTCON0_VBPD(var->upper_margin - 1) | VIDTCON0_VFPD(var->lower_margin - 1) | VIDTCON0_VSPW(var->vsync_len - 1); @@ -574,6 +612,7 @@ static int s3c_fb_set_par(struct fb_info *info) } data = WINCONx_ENWIN; + sfb->enabled |= (1 << win->index); /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out @@ -621,7 +660,8 @@ static int s3c_fb_set_par(struct fb_info *info) } else if (var->transp.length == 1) data |= WINCON1_BPPMODE_25BPP_A1888 | WINCON1_BLD_PIX; - else if (var->transp.length == 4) + else if ((var->transp.length == 4) || + (var->transp.length == 8)) data |= WINCON1_BPPMODE_28BPP_A4888 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else @@ -654,6 +694,8 @@ static int s3c_fb_set_par(struct fb_info *info) shadow_protect_win(win, 0); + pm_runtime_put_sync(sfb->dev); + return 0; } @@ -725,6 +767,8 @@ static int s3c_fb_setcolreg(unsigned regno, dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", __func__, win->index, regno, red, green, blue); + pm_runtime_get_sync(sfb->dev); + switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: /* true-colour, use pseudo-palette */ @@ -752,39 +796,15 @@ static int s3c_fb_setcolreg(unsigned regno, break; default: + pm_runtime_put_sync(sfb->dev); return 1; /* unknown type */ } + pm_runtime_put_sync(sfb->dev); return 0; } /** - * s3c_fb_enable() - Set the state of the main LCD output - * @sfb: The main framebuffer state. - * @enable: The state to set. - */ -static void s3c_fb_enable(struct s3c_fb *sfb, int enable) -{ - u32 vidcon0 = readl(sfb->regs + VIDCON0); - - if (enable) - vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; - else { - /* see the note in the framebuffer datasheet about - * why you cannot take both of these bits down at the - * same time. */ - - if (!(vidcon0 & VIDCON0_ENVID)) - return; - - vidcon0 |= VIDCON0_ENVID; - vidcon0 &= ~VIDCON0_ENVID_F; - } - - writel(vidcon0, sfb->regs + VIDCON0); -} - -/** * s3c_fb_blank() - blank or unblank the given window * @blank_mode: The blank state from FB_BLANK_* * @info: The framebuffer to blank. @@ -800,6 +820,8 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); + pm_runtime_get_sync(sfb->dev); + wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); switch (blank_mode) { @@ -810,12 +832,16 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_NORMAL: /* disable the DMA and display 0x0 (black) */ + shadow_protect_win(win, 1); writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), sfb->regs + sfb->variant.winmap + (index * 4)); + shadow_protect_win(win, 0); break; case FB_BLANK_UNBLANK: + shadow_protect_win(win, 1); writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); + shadow_protect_win(win, 0); wincon |= WINCONx_ENWIN; sfb->enabled |= (1 << index); break; @@ -823,10 +849,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: default: + pm_runtime_put_sync(sfb->dev); return 1; } + shadow_protect_win(win, 1); writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); + shadow_protect_win(win, 0); /* Check the enabled state to see if we need to be running the * main LCD interface, as if there are no active windows then @@ -845,8 +874,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) /* we're stuck with this until we can do something about overriding * the power control using the blanking event for a single fb. */ - if (index == sfb->pdata->default_win) + if (index == sfb->pdata->default_win) { + shadow_protect_win(win, 1); s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); + shadow_protect_win(win, 0); + } + + pm_runtime_put_sync(sfb->dev); return 0; } @@ -870,6 +904,8 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, void __iomem *buf = sfb->regs + win->index * 8; unsigned int start_boff, end_boff; + pm_runtime_get_sync(sfb->dev); + /* Offset in bytes to the start of the displayed area */ start_boff = var->yoffset * info->fix.line_length; /* X offset depends on the current bpp */ @@ -888,6 +924,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, break; default: dev_err(sfb->dev, "invalid bpp\n"); + pm_runtime_put_sync(sfb->dev); return -EINVAL; } } @@ -903,6 +940,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, shadow_protect_win(win, 0); + pm_runtime_put_sync(sfb->dev); return 0; } @@ -992,11 +1030,16 @@ static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc) if (crtc != 0) return -ENODEV; + pm_runtime_get_sync(sfb->dev); + count = sfb->vsync_info.count; s3c_fb_enable_irq(sfb); ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, count != sfb->vsync_info.count, msecs_to_jiffies(VSYNC_TIMEOUT_MSEC)); + + pm_runtime_put_sync(sfb->dev); + if (ret == 0) return -ETIMEDOUT; @@ -1027,30 +1070,8 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, return ret; } -static int s3c_fb_open(struct fb_info *info, int user) -{ - struct s3c_fb_win *win = info->par; - struct s3c_fb *sfb = win->parent; - - pm_runtime_get_sync(sfb->dev); - - return 0; -} - -static int s3c_fb_release(struct fb_info *info, int user) -{ - struct s3c_fb_win *win = info->par; - struct s3c_fb *sfb = win->parent; - - pm_runtime_put_sync(sfb->dev); - - return 0; -} - static struct fb_ops s3c_fb_ops = { .owner = THIS_MODULE, - .fb_open = s3c_fb_open, - .fb_release = s3c_fb_release, .fb_check_var = s3c_fb_check_var, .fb_set_par = s3c_fb_set_par, .fb_blank = s3c_fb_blank, @@ -1452,7 +1473,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) dev_err(dev, "failed to create window %d\n", win); for (; win >= 0; win--) s3c_fb_release_win(sfb, sfb->windows[win]); - goto err_irq; + goto err_pm_runtime; } } @@ -1461,7 +1482,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) return 0; -err_irq: +err_pm_runtime: + pm_runtime_put_sync(sfb->dev); free_irq(sfb->irq_no, sfb); err_ioremap: @@ -1471,6 +1493,8 @@ err_req_region: release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); err_lcd_clk: + pm_runtime_disable(sfb->dev); + if (!sfb->variant.has_clksel) { clk_disable(sfb->lcd_clk); clk_put(sfb->lcd_clk); @@ -1524,7 +1548,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int s3c_fb_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -1571,10 +1595,15 @@ static int s3c_fb_resume(struct device *dev) for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { void __iomem *regs = sfb->regs + sfb->variant.keycon; + win = sfb->windows[win_no]; + if (!win) + continue; + shadow_protect_win(win, 1); regs += (win_no * 8); writel(0xffffff, regs + WKEYCON0); writel(0xffffff, regs + WKEYCON1); + shadow_protect_win(win, 0); } /* restore framebuffers */ @@ -1589,27 +1618,19 @@ static int s3c_fb_resume(struct device *dev) return 0; } +#endif +#ifdef CONFIG_PM_RUNTIME static int s3c_fb_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s3c_fb *sfb = platform_get_drvdata(pdev); - struct s3c_fb_win *win; - int win_no; - - for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { - win = sfb->windows[win_no]; - if (!win) - continue; - - /* use the blank function to push into power-down */ - s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); - } if (!sfb->variant.has_clksel) clk_disable(sfb->lcd_clk); clk_disable(sfb->bus_clk); + return 0; } @@ -1618,8 +1639,6 @@ static int s3c_fb_runtime_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s3c_fb *sfb = platform_get_drvdata(pdev); struct s3c_fb_platdata *pd = sfb->pdata; - struct s3c_fb_win *win; - int win_no; clk_enable(sfb->bus_clk); @@ -1630,39 +1649,10 @@ static int s3c_fb_runtime_resume(struct device *dev) pd->setup_gpio(); writel(pd->vidcon1, sfb->regs + VIDCON1); - /* zero all windows before we do anything */ - for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) - s3c_fb_clear_win(sfb, win_no); - - for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { - void __iomem *regs = sfb->regs + sfb->variant.keycon; - - regs += (win_no * 8); - writel(0xffffff, regs + WKEYCON0); - writel(0xffffff, regs + WKEYCON1); - } - - /* restore framebuffers */ - for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { - win = sfb->windows[win_no]; - if (!win) - continue; - - dev_dbg(&pdev->dev, "resuming window %d\n", win_no); - s3c_fb_set_par(win->fbinfo); - } - return 0; } - -#else -#define s3c_fb_suspend NULL -#define s3c_fb_resume NULL -#define s3c_fb_runtime_suspend NULL -#define s3c_fb_runtime_resume NULL #endif - #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) @@ -1985,10 +1975,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = { MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); static const struct dev_pm_ops s3cfb_pm_ops = { - .suspend = s3c_fb_suspend, - .resume = s3c_fb_resume, - .runtime_suspend = s3c_fb_runtime_suspend, - .runtime_resume = s3c_fb_runtime_resume, + SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume) + SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume, + NULL) }; static struct platform_driver s3c_fb_driver = { @@ -2002,18 +1991,7 @@ static struct platform_driver s3c_fb_driver = { }, }; -static int __init s3c_fb_init(void) -{ - return platform_driver_register(&s3c_fb_driver); -} - -static void __exit s3c_fb_cleanup(void) -{ - platform_driver_unregister(&s3c_fb_driver); -} - -module_init(s3c_fb_init); -module_exit(s3c_fb_cleanup); +module_platform_driver(s3c_fb_driver); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ee4c0df217f7..77f34c614c86 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -26,8 +26,8 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/cpufreq.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/div64.h> #include <asm/mach/map.h> @@ -45,10 +45,10 @@ #ifdef CONFIG_FB_S3C2410_DEBUG static int debug = 1; #else -static int debug = 0; +static int debug; #endif -#define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } +#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg); /* useful functions */ @@ -567,11 +567,10 @@ static int s3c2410fb_blank(int blank_mode, struct fb_info *info) tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; - if (blank_mode == FB_BLANK_POWERDOWN) { + if (blank_mode == FB_BLANK_POWERDOWN) s3c2410fb_lcd_enable(fbi, 0); - } else { + else s3c2410fb_lcd_enable(fbi, 1); - } if (blank_mode == FB_BLANK_UNBLANK) writel(0x0, tpal_reg); @@ -812,7 +811,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) #endif -static char driver_name[] = "s3c2410fb"; +static const char driver_name[] = "s3c2410fb"; static int __devinit s3c24xxfb_probe(struct platform_device *pdev, enum s3c_drv_type drv_type) @@ -881,7 +880,10 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, goto release_mem; } - info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE); + if (drv_type == DRV_S3C2412) + info->irq_base = info->io + S3C2412_LCDINTBASE; + else + info->irq_base = info->io + S3C2410_LCDINTBASE; dprintk("devinit\n"); @@ -927,7 +929,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, clk_enable(info->clk); dprintk("got and enabled clock\n"); - msleep(1); + usleep_range(1000, 1000); info->clk_rate = clk_get_rate(info->clk); @@ -975,9 +977,8 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, /* create device files */ ret = device_create_file(&pdev->dev, &dev_attr_debug); - if (ret) { + if (ret) printk(KERN_ERR "failed to add debug attribute\n"); - } printk(KERN_INFO "fb%d: %s frame buffer device\n", fbinfo->node, fbinfo->fix.id); @@ -1027,7 +1028,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev) s3c2410fb_cpufreq_deregister(info); s3c2410fb_lcd_enable(info, 0); - msleep(1); + usleep_range(1000, 1000); s3c2410fb_unmap_video_memory(fbinfo); @@ -1064,7 +1065,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) * the LCD DMA engine is not going to get back on the bus * before the clock goes off again (bjd) */ - msleep(1); + usleep_range(1000, 1000); clk_disable(info->clk); return 0; @@ -1076,7 +1077,7 @@ static int s3c2410fb_resume(struct platform_device *dev) struct s3c2410fb_info *info = fbinfo->par; clk_enable(info->clk); - msleep(1); + usleep_range(1000, 1000); s3c2410fb_init_registers(fbinfo); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 946a949f4c7d..2c80246b18b8 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -727,7 +727,7 @@ static int s3fb_set_par(struct fb_info *info) if (par->chip == CHIP_988_VIRGE_VX) { vga_wcrt(par->state.vgabase, 0x50, 0x00); vga_wcrt(par->state.vgabase, 0x67, 0x50); - + msleep(10); /* screen remains blank sometimes without this */ vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); vga_wcrt(par->state.vgabase, 0x66, 0x90); } @@ -901,7 +901,8 @@ static int s3fb_set_par(struct fb_info *info) /* Set Data Transfer Position */ hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8; - value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1); + /* + 2 is needed for Virge/VX, does no harm on other cards */ + value = clamp((htotal + hsstart + 1) / 2 + 2, hsstart + 4, htotal + 1); svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value); memset_io(info->screen_base, 0x00, screen_size); @@ -1216,6 +1217,31 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_size = 2 << 20; break; } + } else if (par->chip == CHIP_988_VIRGE_VX) { + switch ((regval & 0x60) >> 5) { + case 0: /* 2MB */ + info->screen_size = 2 << 20; + break; + case 1: /* 4MB */ + info->screen_size = 4 << 20; + break; + case 2: /* 6MB */ + info->screen_size = 6 << 20; + break; + case 3: /* 8MB */ + info->screen_size = 8 << 20; + break; + } + /* off-screen memory */ + regval = vga_rcrt(par->state.vgabase, 0x37); + switch ((regval & 0x60) >> 5) { + case 1: /* 4MB */ + info->screen_size -= 4 << 20; + break; + case 2: /* 2MB */ + info->screen_size -= 2 << 20; + break; + } } else info->screen_size = s3_memsizes[regval >> 5] << 10; info->fix.smem_len = info->screen_size; diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c index 37d764ad56b0..3c1de981a18c 100644 --- a/drivers/video/sbuslib.c +++ b/drivers/video/sbuslib.c @@ -76,7 +76,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, map_offset = (physbase + map[i].poff) & POFF_MASK; break; } - if (!map_size){ + if (!map_size) { page += PAGE_SIZE; continue; } diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 45e47d847163..83b16e237a0e 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -585,18 +585,7 @@ static struct platform_driver sh7760_lcdc_driver = { .remove = __devexit_p(sh7760fb_remove), }; -static int __init sh7760fb_init(void) -{ - return platform_driver_register(&sh7760_lcdc_driver); -} - -static void __exit sh7760fb_exit(void) -{ - platform_driver_unregister(&sh7760_lcdc_driver); -} - -module_init(sh7760fb_init); -module_exit(sh7760fb_exit); +module_platform_driver(sh7760_lcdc_driver); MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss"); MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller"); diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 72ee96bc6b3e..05151b82f40f 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include <linux/bitmap.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/init.h> @@ -41,6 +42,7 @@ #define VMCTR1 0x0020 #define VMCTR2 0x0024 #define VMLEN1 0x0028 +#define VMLEN2 0x002c #define CMTSRTREQ 0x0070 #define CMTSRTCTR 0x00d0 @@ -51,8 +53,7 @@ struct sh_mipi { void __iomem *base; void __iomem *linkbase; struct clk *dsit_clk; - struct clk *dsip_clk; - struct device *dev; + struct platform_device *pdev; void *next_board_data; void (*next_display_on)(void *board_data, struct fb_info *info); @@ -124,35 +125,15 @@ static void sh_mipi_shutdown(struct platform_device *pdev) sh_mipi_dsi_enable(mipi, false); } -static void mipi_display_on(void *arg, struct fb_info *info) -{ - struct sh_mipi *mipi = arg; - - pm_runtime_get_sync(mipi->dev); - sh_mipi_dsi_enable(mipi, true); - - if (mipi->next_display_on) - mipi->next_display_on(mipi->next_board_data, info); -} - -static void mipi_display_off(void *arg) -{ - struct sh_mipi *mipi = arg; - - if (mipi->next_display_off) - mipi->next_display_off(mipi->next_board_data); - - sh_mipi_dsi_enable(mipi, false); - pm_runtime_put(mipi->dev); -} - static int __init sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) { void __iomem *base = mipi->base; struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; - u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000; + u32 pctype, datatype, pixfmt, linelength, vmctr2; + u32 tmp, top, bottom, delay, div; bool yuv; + int bpp; /* * Select data format. MIPI DSI is not hot-pluggable, so, we just use @@ -253,6 +234,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, (!yuv && ch->interface_type != RGB24)) return -EINVAL; + if (!pdata->lane) + return -EINVAL; + /* reset DSI link */ iowrite32(0x00000001, base + SYSCTRL); /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */ @@ -262,15 +246,6 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, /* setup DSI link */ /* - * Default = ULPS enable | - * Contention detection enabled | - * EoT packet transmission enable | - * CRC check enable | - * ECC check enable - * additionally enable first two lanes - */ - iowrite32(0x00003703, base + SYSCONF); - /* * T_wakeup = 0x7000 * T_hs-trail = 3 * T_hs-prepare = 3 @@ -290,15 +265,24 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, iowrite32(0x0fffffff, base + TATOVSET); /* Peripheral reset timeout, default 0xffffffff */ iowrite32(0x0fffffff, base + PRTOVSET); - /* Enable timeout counters */ - iowrite32(0x00000f00, base + DSICTRL); /* Interrupts not used, disable all */ iowrite32(0, base + DSIINTE); /* DSI-Tx bias on */ iowrite32(0x00000001, base + PHYCTRL); udelay(200); - /* Deassert resets, power on, set multiplier */ - iowrite32(0x03070b01, base + PHYCTRL); + /* Deassert resets, power on */ + iowrite32(0x03070001, base + PHYCTRL); + + /* + * Default = ULPS enable | + * Contention detection enabled | + * EoT packet transmission enable | + * CRC check enable | + * ECC check enable + */ + bitmap_fill((unsigned long *)&tmp, pdata->lane); + tmp |= 0x00003700; + iowrite32(tmp, base + SYSCONF); /* setup l-bridge */ @@ -316,18 +300,68 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, * Non-burst mode with sync pulses: VSE and HSE are output, * HSA period allowed, no commands in LP */ + vmctr2 = 0; + if (pdata->flags & SH_MIPI_DSI_VSEE) + vmctr2 |= 1 << 23; + if (pdata->flags & SH_MIPI_DSI_HSEE) + vmctr2 |= 1 << 22; + if (pdata->flags & SH_MIPI_DSI_HSAE) + vmctr2 |= 1 << 21; + if (pdata->flags & SH_MIPI_DSI_BL2E) + vmctr2 |= 1 << 17; if (pdata->flags & SH_MIPI_DSI_HSABM) - vmctr2 |= 0x20; - if (pdata->flags & SH_MIPI_DSI_HSPBM) - vmctr2 |= 0x10; + vmctr2 |= 1 << 5; + if (pdata->flags & SH_MIPI_DSI_HBPBM) + vmctr2 |= 1 << 4; + if (pdata->flags & SH_MIPI_DSI_HFPBM) + vmctr2 |= 1 << 3; iowrite32(vmctr2, mipi->linkbase + VMCTR2); /* - * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see - * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default - * (unused if VMCTR2[HSABM] = 0) + * VMLEN1 = RGBLEN | HSALEN + * + * see + * Video mode - Blanking Packet setting + */ + top = linelength << 16; /* RGBLEN */ + bottom = 0x00000001; + if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ + bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10; + iowrite32(top | bottom , mipi->linkbase + VMLEN1); + + /* + * VMLEN2 = HBPLEN | HFPLEN + * + * see + * Video mode - Blanking Packet setting */ - iowrite32(1 | (linelength << 16), mipi->linkbase + VMLEN1); + top = 0x00010000; + bottom = 0x00000001; + delay = 0; + + div = 1; /* HSbyteCLK is calculation base + * HS4divCLK = HSbyteCLK/2 + * HS6divCLK is not supported for now */ + if (pdata->flags & SH_MIPI_DSI_HS4divCLK) + div = 2; + + if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ + top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin; + top = ((pdata->lane * top / div) - 10) << 16; + } + if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ + bottom = ch->lcd_cfg[0].right_margin; + bottom = (pdata->lane * bottom / div) - 12; + } + + bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */ + if ((pdata->lane / div) > bpp) { + tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */ + tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */ + delay = (pdata->lane * tmp); + } + + iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2); msleep(5); @@ -352,9 +386,56 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, pixfmt << 4); sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON); + /* Enable timeout counters */ + iowrite32(0x00000f00, base + DSICTRL); + return 0; } +static void mipi_display_on(void *arg, struct fb_info *info) +{ + struct sh_mipi *mipi = arg; + struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; + int ret; + + pm_runtime_get_sync(&mipi->pdev->dev); + + ret = pdata->set_dot_clock(mipi->pdev, mipi->base, 1); + if (ret < 0) + goto mipi_display_on_fail1; + + ret = sh_mipi_setup(mipi, pdata); + if (ret < 0) + goto mipi_display_on_fail2; + + sh_mipi_dsi_enable(mipi, true); + + if (mipi->next_display_on) + mipi->next_display_on(mipi->next_board_data, info); + + return; + +mipi_display_on_fail1: + pm_runtime_put_sync(&mipi->pdev->dev); +mipi_display_on_fail2: + pdata->set_dot_clock(mipi->pdev, mipi->base, 0); +} + +static void mipi_display_off(void *arg) +{ + struct sh_mipi *mipi = arg; + struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; + + if (mipi->next_display_off) + mipi->next_display_off(mipi->next_board_data); + + sh_mipi_dsi_enable(mipi, false); + + pdata->set_dot_clock(mipi->pdev, mipi->base, 0); + + pm_runtime_put_sync(&mipi->pdev->dev); +} + static int __init sh_mipi_probe(struct platform_device *pdev) { struct sh_mipi *mipi; @@ -363,11 +444,13 @@ static int __init sh_mipi_probe(struct platform_device *pdev) struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); unsigned long rate, f_current; int idx = pdev->id, ret; - char dsip_clk[] = "dsi.p_clk"; if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata) return -ENODEV; + if (!pdata->set_dot_clock) + return -EINVAL; + mutex_lock(&array_lock); if (idx < 0) for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++) @@ -408,7 +491,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) goto emap2; } - mipi->dev = &pdev->dev; + mipi->pdev = pdev; mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk"); if (IS_ERR(mipi->dsit_clk)) { @@ -428,44 +511,15 @@ static int __init sh_mipi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate); - sprintf(dsip_clk, "dsi%1.1dp_clk", idx); - mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk); - if (IS_ERR(mipi->dsip_clk)) { - ret = PTR_ERR(mipi->dsip_clk); - goto eclkpget; - } - - f_current = clk_get_rate(mipi->dsip_clk); - /* Between 10 and 50MHz */ - rate = clk_round_rate(mipi->dsip_clk, 24000000); - if (rate > 0 && rate != f_current) - ret = clk_set_rate(mipi->dsip_clk, rate); - else - ret = rate; - if (ret < 0) - goto esetprate; - - dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate); - - msleep(10); - ret = clk_enable(mipi->dsit_clk); if (ret < 0) goto eclkton; - ret = clk_enable(mipi->dsip_clk); - if (ret < 0) - goto eclkpon; - mipi_dsi[idx] = mipi; pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); - ret = sh_mipi_setup(mipi, pdata); - if (ret < 0) - goto emipisetup; - mutex_unlock(&array_lock); platform_set_drvdata(pdev, mipi); @@ -482,16 +536,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) return 0; -emipisetup: - mipi_dsi[idx] = NULL; - pm_runtime_disable(&pdev->dev); - clk_disable(mipi->dsip_clk); -eclkpon: - clk_disable(mipi->dsit_clk); eclkton: -esetprate: - clk_put(mipi->dsip_clk); -eclkpget: esettrate: clk_put(mipi->dsit_clk); eclktget: @@ -542,10 +587,9 @@ static int __exit sh_mipi_remove(struct platform_device *pdev) pdata->lcd_chan->board_cfg.board_data = NULL; pm_runtime_disable(&pdev->dev); - clk_disable(mipi->dsip_clk); clk_disable(mipi->dsit_clk); clk_put(mipi->dsit_clk); - clk_put(mipi->dsip_clk); + iounmap(mipi->linkbase); if (res2) release_mem_region(res2->start, resource_size(res2)); diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index facffc254976..aac5b369d73c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/ioctl.h> #include <linux/slab.h> @@ -102,7 +103,7 @@ struct sh_mobile_lcdc_priv { struct sh_mobile_lcdc_chan ch[2]; struct notifier_block notifier; int started; - int forced_bpp; /* 2 channel LCDC must share bpp setting */ + int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ struct sh_mobile_meram_info *meram_dev; }; @@ -215,6 +216,47 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { lcdc_sys_read_data, }; +static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) +{ + if (var->grayscale > 1) + return var->grayscale; + + switch (var->bits_per_pixel) { + case 16: + return V4L2_PIX_FMT_RGB565; + case 24: + return V4L2_PIX_FMT_BGR24; + case 32: + return V4L2_PIX_FMT_BGR32; + default: + return 0; + } +} + +static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) +{ + return var->grayscale > 1; +} + +static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var) +{ + if (var->grayscale <= 1) + return false; + + switch (var->grayscale) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + return true; + + default: + return false; + } +} + static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) { if (atomic_inc_and_test(&priv->hw_usecnt)) { @@ -420,7 +462,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) tmp = ((display_var->xres & 7) << 24) | ((display_h_total & 7) << 16) | ((display_var->hsync_len & 7) << 8) | - hsync_pos; + (hsync_pos & 7); lcdc_write_chan(ch, LDHAJR, tmp); } @@ -435,7 +477,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; unsigned long tmp; - int bpp = 0; int k, m; /* Enable LCDC channels. Read data from external memory, avoid using the @@ -454,9 +495,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) if (!ch->enabled) continue; - if (!bpp) - bpp = ch->info->var.bits_per_pixel; - /* Power supply */ lcdc_write_chan(ch, LDPMR, 0); @@ -487,31 +525,37 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) sh_mobile_lcdc_geometry(ch); - if (ch->info->var.nonstd) { - tmp = (ch->info->var.nonstd << 16); - switch (ch->info->var.bits_per_pixel) { - case 12: - tmp |= LDDFR_YF_420; - break; - case 16: - tmp |= LDDFR_YF_422; - break; - case 24: - default: - tmp |= LDDFR_YF_444; - break; - } - } else { - switch (ch->info->var.bits_per_pixel) { - case 16: - tmp = LDDFR_PKF_RGB16; - break; - case 24: - tmp = LDDFR_PKF_RGB24; + switch (sh_mobile_format_fourcc(&ch->info->var)) { + case V4L2_PIX_FMT_RGB565: + tmp = LDDFR_PKF_RGB16; + break; + case V4L2_PIX_FMT_BGR24: + tmp = LDDFR_PKF_RGB24; + break; + case V4L2_PIX_FMT_BGR32: + tmp = LDDFR_PKF_ARGB32; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + tmp = LDDFR_CC | LDDFR_YF_420; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + tmp = LDDFR_CC | LDDFR_YF_422; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tmp = LDDFR_CC | LDDFR_YF_444; + break; + } + + if (sh_mobile_format_is_yuv(&ch->info->var)) { + switch (ch->info->var.colorspace) { + case V4L2_COLORSPACE_REC709: + tmp |= LDDFR_CF1; break; - case 32: - default: - tmp = LDDFR_PKF_ARGB32; + case V4L2_COLORSPACE_JPEG: + tmp |= LDDFR_CF0; break; } } @@ -519,7 +563,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) lcdc_write_chan(ch, LDDFR, tmp); lcdc_write_chan(ch, LDMLSR, ch->pitch); lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); - if (ch->info->var.nonstd) + if (sh_mobile_format_is_yuv(&ch->info->var)) lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); /* When using deferred I/O mode, configure the LCDC for one-shot @@ -536,21 +580,23 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) } /* Word and long word swap. */ - if (priv->ch[0].info->var.nonstd) + switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV42: + tmp = LDDDSR_LS | LDDDSR_WS; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV24: tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - else { - switch (bpp) { - case 16: - tmp = LDDDSR_LS | LDDDSR_WS; - break; - case 24: - tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - break; - case 32: - default: - tmp = LDDDSR_LS; - break; - } + break; + case V4L2_PIX_FMT_BGR32: + default: + tmp = LDDDSR_LS; + break; } lcdc_write(priv, _LDDDSR, tmp); @@ -622,12 +668,24 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->meram_enabled = 0; } - if (!ch->info->var.nonstd) - pixelformat = SH_MOBILE_MERAM_PF_RGB; - else if (ch->info->var.bits_per_pixel == 24) - pixelformat = SH_MOBILE_MERAM_PF_NV24; - else + switch (sh_mobile_format_fourcc(&ch->info->var)) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: pixelformat = SH_MOBILE_MERAM_PF_NV; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + pixelformat = SH_MOBILE_MERAM_PF_NV24; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_BGR32: + default: + pixelformat = SH_MOBILE_MERAM_PF_RGB; + break; + } ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, ch->info->var.yres, pixelformat, @@ -845,6 +903,7 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { .xpanstep = 0, .ypanstep = 1, .ywrapstep = 0, + .capabilities = FB_CAP_FOURCC, }; static void sh_mobile_lcdc_fillrect(struct fb_info *info, @@ -877,8 +936,9 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, unsigned long new_pan_offset; unsigned long base_addr_y, base_addr_c; unsigned long c_offset; + bool yuv = sh_mobile_format_is_yuv(&info->var); - if (!info->var.nonstd) + if (!yuv) new_pan_offset = var->yoffset * info->fix.line_length + var->xoffset * (info->var.bits_per_pixel / 8); else @@ -892,7 +952,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, /* Set the source address for the next refresh */ base_addr_y = ch->dma_handle + new_pan_offset; - if (info->var.nonstd) { + if (yuv) { /* Set y offset */ c_offset = var->yoffset * info->fix.line_length * (info->var.bits_per_pixel - 8) / 8; @@ -900,7 +960,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, + info->var.xres * info->var.yres_virtual + c_offset; /* Set x offset */ - if (info->var.bits_per_pixel == 24) + if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24) base_addr_c += 2 * var->xoffset; else base_addr_c += var->xoffset; @@ -924,7 +984,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, ch->base_addr_c = base_addr_c; lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); - if (info->var.nonstd) + if (yuv) lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); if (lcdc_chan_is_sublcd(ch)) @@ -1100,51 +1160,84 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; - if (var->bits_per_pixel <= 16) { /* RGB 565 */ - var->bits_per_pixel = 16; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ - var->bits_per_pixel = 24; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ - var->bits_per_pixel = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - } else - return -EINVAL; + if (sh_mobile_format_is_fourcc(var)) { + switch (var->grayscale) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + var->bits_per_pixel = 12; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + var->bits_per_pixel = 16; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + var->bits_per_pixel = 24; + break; + case V4L2_PIX_FMT_BGR32: + var->bits_per_pixel = 32; + break; + default: + return -EINVAL; + } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; + /* Default to RGB and JPEG color-spaces for RGB and YUV formats + * respectively. + */ + if (!sh_mobile_format_is_yuv(var)) + var->colorspace = V4L2_COLORSPACE_SRGB; + else if (var->colorspace != V4L2_COLORSPACE_REC709) + var->colorspace = V4L2_COLORSPACE_JPEG; + } else { + if (var->bits_per_pixel <= 16) { /* RGB 565 */ + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ + var->bits_per_pixel = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + } else + return -EINVAL; + + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + } /* Make sure we don't exceed our allocated memory. */ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > info->fix.smem_len) return -EINVAL; - /* only accept the forced_bpp for dual channel configurations */ - if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) + /* only accept the forced_fourcc for dual channel configurations */ + if (p->forced_fourcc && + p->forced_fourcc != sh_mobile_format_fourcc(var)) return -EINVAL; return 0; @@ -1158,7 +1251,7 @@ static int sh_mobile_set_par(struct fb_info *info) sh_mobile_lcdc_stop(ch->lcdc); - if (info->var.nonstd) + if (sh_mobile_format_is_yuv(&info->var)) info->fix.line_length = info->var.xres; else info->fix.line_length = info->var.xres @@ -1170,6 +1263,14 @@ static int sh_mobile_set_par(struct fb_info *info) info->fix.line_length = line_length; } + if (sh_mobile_format_is_fourcc(&info->var)) { + info->fix.type = FB_TYPE_FOURCC; + info->fix.visual = FB_VISUAL_FOURCC; + } else { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + } + return ret; } @@ -1464,9 +1565,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { unsigned int size = mode->yres * mode->xres; - /* NV12 buffers must have even number of lines */ - if ((cfg->nonstd) && cfg->bpp == 12 && - (mode->yres & 0x1)) { + /* NV12/NV21 buffers must have even number of lines */ + if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || + cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { dev_err(dev, "yres must be multiple of 2 for YCbCr420 " "mode.\n"); return -EINVAL; @@ -1484,14 +1585,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, dev_dbg(dev, "Found largest videomode %ux%u\n", max_mode->xres, max_mode->yres); - /* Initialize fixed screen information. Restrict pan to 2 lines steps - * for NV12. - */ - info->fix = sh_mobile_lcdc_fix; - info->fix.smem_len = max_size * 2 * cfg->bpp / 8; - if (cfg->nonstd && cfg->bpp == 12) - info->fix.ypanstep = 2; - /* Create the mode list. */ if (cfg->lcd_cfg == NULL) { mode = &default_720p; @@ -1509,19 +1602,38 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, */ var = &info->var; fb_videomode_to_var(var, mode); - var->bits_per_pixel = cfg->bpp; var->width = cfg->lcd_size_cfg.width; var->height = cfg->lcd_size_cfg.height; var->yres_virtual = var->yres * 2; var->activate = FB_ACTIVATE_NOW; + switch (cfg->fourcc) { + case V4L2_PIX_FMT_RGB565: + var->bits_per_pixel = 16; + break; + case V4L2_PIX_FMT_BGR24: + var->bits_per_pixel = 24; + break; + case V4L2_PIX_FMT_BGR32: + var->bits_per_pixel = 32; + break; + default: + var->grayscale = cfg->fourcc; + break; + } + + /* Make sure the memory size check won't fail. smem_len is initialized + * later based on var. + */ + info->fix.smem_len = UINT_MAX; ret = sh_mobile_check_var(var, info); if (ret) return ret; + max_size = max_size * var->bits_per_pixel / 8 * 2; + /* Allocate frame buffer memory and color map. */ - buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle, - GFP_KERNEL); + buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL); if (!buf) { dev_err(dev, "unable to allocate buffer\n"); return -ENOMEM; @@ -1530,16 +1642,27 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); if (ret < 0) { dev_err(dev, "unable to allocate cmap\n"); - dma_free_coherent(dev, info->fix.smem_len, - buf, ch->dma_handle); + dma_free_coherent(dev, max_size, buf, ch->dma_handle); return ret; } + /* Initialize fixed screen information. Restrict pan to 2 lines steps + * for NV12 and NV21. + */ + info->fix = sh_mobile_lcdc_fix; info->fix.smem_start = ch->dma_handle; - if (var->nonstd) + info->fix.smem_len = max_size; + if (cfg->fourcc == V4L2_PIX_FMT_NV12 || + cfg->fourcc == V4L2_PIX_FMT_NV21) + info->fix.ypanstep = 2; + + if (sh_mobile_format_is_yuv(var)) { info->fix.line_length = var->xres; - else - info->fix.line_length = var->xres * (cfg->bpp / 8); + info->fix.visual = FB_VISUAL_FOURCC; + } else { + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + info->fix.visual = FB_VISUAL_TRUECOLOR; + } info->screen_base = buf; info->device = dev; @@ -1626,9 +1749,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } - /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ + /* for dual channel LCDC (MAIN + SUB) force shared format setting */ if (num_channels == 2) - priv->forced_bpp = pdata->ch[0].bpp; + priv->forced_fourcc = pdata->ch[0].fourcc; priv->base = ioremap_nocache(res->start, resource_size(res)); if (!priv->base) @@ -1675,13 +1798,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) if (error < 0) goto err1; - dev_info(info->dev, - "registered %s/%s as %dx%d %dbpp.\n", - pdev->name, - (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? - "mainlcd" : "sublcd", - info->var.xres, info->var.yres, - ch->cfg.bpp); + dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n", + pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? + "mainlcd" : "sublcd", info->var.xres, info->var.yres, + info->var.bits_per_pixel); /* deferred io mode: disable clock to save power */ if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) @@ -1709,18 +1829,7 @@ static struct platform_driver sh_mobile_lcdc_driver = { .remove = sh_mobile_lcdc_remove, }; -static int __init sh_mobile_lcdc_init(void) -{ - return platform_driver_register(&sh_mobile_lcdc_driver); -} - -static void __exit sh_mobile_lcdc_exit(void) -{ - platform_driver_unregister(&sh_mobile_lcdc_driver); -} - -module_init(sh_mobile_lcdc_init); -module_exit(sh_mobile_lcdc_exit); +module_platform_driver(sh_mobile_lcdc_driver); MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index 4d63490209cd..f45d83ecfd21 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c @@ -679,18 +679,7 @@ static struct platform_driver sh_mobile_meram_driver = { .remove = sh_mobile_meram_remove, }; -static int __init sh_mobile_meram_init(void) -{ - return platform_driver_register(&sh_mobile_meram_driver); -} - -static void __exit sh_mobile_meram_exit(void) -{ - platform_driver_unregister(&sh_mobile_meram_driver); -} - -module_init(sh_mobile_meram_init); -module_exit(sh_mobile_meram_exit); +module_platform_driver(sh_mobile_meram_driver); MODULE_DESCRIPTION("SuperH Mobile MERAM driver"); MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama"); diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index a78254cf8e83..3690effbedcc 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -2230,18 +2230,7 @@ static struct platform_driver sm501fb_driver = { }, }; -static int __devinit sm501fb_init(void) -{ - return platform_driver_register(&sm501fb_driver); -} - -static void __exit sm501fb_cleanup(void) -{ - platform_driver_unregister(&sm501fb_driver); -} - -module_init(sm501fb_init); -module_exit(sm501fb_cleanup); +module_platform_driver(sm501fb_driver); module_param_named(mode, fb_mode, charp, 0); MODULE_PARM_DESC(mode, diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index 3c22994ea31a..ccbfef5e828f 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c @@ -130,8 +130,8 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); /* module options */ -static int console; /* Optionally allow fbcon to consume first framebuffer */ -static int fb_defio = true; /* Optionally enable fb_defio mmap support */ +static bool console; /* Optionally allow fbcon to consume first framebuffer */ +static bool fb_defio = true; /* Optionally enable fb_defio mmap support */ /* ufx keeps a list of urbs for efficient bulk transfers */ static void ufx_urb_completion(struct urb *urb); diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 2301c275d63a..111fb32e8769 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -93,11 +93,11 @@ /* initialized by setup */ -static int vgapass; /* enable VGA passthrough cable */ +static bool vgapass; /* enable VGA passthrough cable */ static int mem; /* mem size in MB, 0 = autodetect */ -static int clipping = 1; /* use clipping (slower, safer) */ +static bool clipping = 1; /* use clipping (slower, safer) */ static int gfxclk; /* force FBI freq in Mhz . Dangerous */ -static int slowpci; /* slow PCI settings */ +static bool slowpci; /* slow PCI settings */ /* Possible default video modes: 800x600@60, 640x480@75, 1024x768@76, 640x480@60 diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index a99b994c9b6b..e026724a3a56 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -169,7 +169,7 @@ static int nowrap = 1; /* not implemented (yet) */ static int hwcursor = 1; static char *mode_option __devinitdata; /* mtrr option */ -static int nomtrr __devinitdata; +static bool nomtrr __devinitdata; /* ------------------------------------------------------------------------- * Hardware-specific funcions diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 1f868d0187a2..a19773149bd7 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -69,9 +69,9 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); /* module options */ -static int console = 1; /* Allow fbcon to open framebuffer */ -static int fb_defio = 1; /* Detect mmap writes using page faults */ -static int shadow = 1; /* Optionally disable shadow framebuffer */ +static bool console = 1; /* Allow fbcon to open framebuffer */ +static bool fb_defio = 1; /* Detect mmap writes using page faults */ +static bool shadow = 1; /* Optionally disable shadow framebuffer */ /* dlfb keeps a list of urbs for efficient bulk transfers */ static void dlfb_urb_completion(struct urb *urb); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 7f8472cc993b..e7f69ef572dc 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -44,11 +44,11 @@ static struct fb_fix_screeninfo uvesafb_fix __devinitdata = { }; static int mtrr __devinitdata = 3; /* enable mtrr by default */ -static int blank = 1; /* enable blanking by default */ +static bool blank = 1; /* enable blanking by default */ static int ypan = 1; /* 0: scroll, 1: ypan, 2: ywrap */ static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */ -static int nocrtc __devinitdata; /* ignore CRTC settings */ -static int noedid __devinitdata; /* don't try DDC transfers */ +static bool nocrtc __devinitdata; /* ignore CRTC settings */ +static bool noedid __devinitdata; /* don't try DDC transfers */ static int vram_remap __devinitdata; /* set amt. of memory to be used */ static int vram_total __devinitdata; /* set total amount of memory */ static u16 maxclk __devinitdata; /* maximum pixel clock */ diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index bf2f78065cf9..501a922aa9dc 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -110,7 +110,7 @@ static struct fb_fix_screeninfo vfb_fix __devinitdata = { .accel = FB_ACCEL_NONE, }; -static int vfb_enable __initdata = 0; /* disabled by default */ +static bool vfb_enable __initdata = 0; /* disabled by default */ module_param(vfb_enable, bool, 0); static int vfb_check_var(struct fb_var_screeninfo *var, diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 777c21dd7a6b..2a5fe6ede845 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -457,18 +457,7 @@ static struct platform_driver vt8500lcd_driver = { }, }; -static int __init vt8500lcd_init(void) -{ - return platform_driver_register(&vt8500lcd_driver); -} - -static void __exit vt8500lcd_exit(void) -{ - platform_driver_unregister(&vt8500lcd_driver); -} - -module_init(vt8500lcd_init); -module_exit(vt8500lcd_exit); +module_platform_driver(vt8500lcd_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 2375e5bbf572..90a2e30272ad 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -1620,18 +1620,7 @@ static struct platform_driver w100fb_driver = { }, }; -int __init w100fb_init(void) -{ - return platform_driver_register(&w100fb_driver); -} - -void __exit w100fb_cleanup(void) -{ - platform_driver_unregister(&w100fb_driver); -} - -module_init(w100fb_init); -module_exit(w100fb_cleanup); +module_platform_driver(w100fb_driver); MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index 96e34a569169..c8703bd61b74 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c @@ -404,18 +404,7 @@ static struct platform_driver wm8505fb_driver = { }, }; -static int __init wm8505fb_init(void) -{ - return platform_driver_register(&wm8505fb_driver); -} - -static void __exit wm8505fb_exit(void) -{ - platform_driver_unregister(&wm8505fb_driver); -} - -module_init(wm8505fb_init); -module_exit(wm8505fb_exit); +module_platform_driver(wm8505fb_driver); MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c index 45832b7ef7d2..55be3865015b 100644 --- a/drivers/video/wmt_ge_rops.c +++ b/drivers/video/wmt_ge_rops.c @@ -167,18 +167,7 @@ static struct platform_driver wmt_ge_rops_driver = { }, }; -static int __init wmt_ge_rops_init(void) -{ - return platform_driver_register(&wmt_ge_rops_driver); -} - -static void __exit wmt_ge_rops_exit(void) -{ - platform_driver_unregister(&wmt_ge_rops_driver); -} - -module_init(wmt_ge_rops_init); -module_exit(wmt_ge_rops_exit); +module_platform_driver(wmt_ge_rops_driver); MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); MODULE_DESCRIPTION("Accelerators for raster operations using " diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index fcb6cd90f64d..18084525402a 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -511,25 +511,7 @@ static struct platform_driver xilinxfb_of_driver = { }, }; - -/* --------------------------------------------------------------------- - * Module setup and teardown - */ - -static int __init -xilinxfb_init(void) -{ - return platform_driver_register(&xilinxfb_of_driver); -} - -static void __exit -xilinxfb_cleanup(void) -{ - platform_driver_unregister(&xilinxfb_of_driver); -} - -module_init(xilinxfb_init); -module_exit(xilinxfb_cleanup); +module_platform_driver(xilinxfb_of_driver); MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); MODULE_DESCRIPTION("Xilinx TFT frame buffer driver"); diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index d4d8d1fdccc4..e45ca2b4bfbe 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -100,7 +100,7 @@ MODULE_PARM_DESC(f71862fg_pin, "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63" " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")"); -static int nowayout = WATCHDOG_NOWAYOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0444); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index eed5436ffb51..20feb4d3d791 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -55,7 +55,7 @@ module_param(timeout, ushort, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535)"); -static int reset = 1; +static bool reset = 1; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset"); diff --git a/drivers/xen/xen-pciback/conf_space.c b/drivers/xen/xen-pciback/conf_space.c index 52fed16d8701..30d7be026c18 100644 --- a/drivers/xen/xen-pciback/conf_space.c +++ b/drivers/xen/xen-pciback/conf_space.c @@ -16,7 +16,7 @@ #include "conf_space.h" #include "conf_space_quirks.h" -static int permissive; +static bool permissive; module_param(permissive, bool, 0644); /* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word, diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index 8e1c44d8ab46..d5dcf8d5d3d9 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c @@ -16,7 +16,7 @@ #define INVALID_EVTCHN_IRQ (-1) struct workqueue_struct *xen_pcibk_wq; -static int __read_mostly passthrough; +static bool __read_mostly passthrough; module_param(passthrough, bool, S_IRUGO); MODULE_PARM_DESC(passthrough, "Option to specify how to export PCI topology to guest:\n"\ |