diff options
Diffstat (limited to 'drivers')
354 files changed, 11727 insertions, 3937 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 3d93b3a3d630..dd0a5b5e9bf3 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -88,6 +88,8 @@ source "drivers/memstick/Kconfig" source "drivers/leds/Kconfig" +source "drivers/nfc/Kconfig" + source "drivers/accessibility/Kconfig" source "drivers/infiniband/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index bf15ce7493d2..ef5132469f58 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -40,7 +40,7 @@ obj-$(CONFIG_FB_INTEL) += video/intelfb/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ -obj-y += base/ block/ misc/ mfd/ +obj-y += base/ block/ misc/ mfd/ nfc/ obj-$(CONFIG_NUBUS) += nubus/ obj-y += macintosh/ obj-$(CONFIG_IDE) += ide/ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index bdbfaf22bd14..962a3ccff6fd 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -93,7 +93,7 @@ #define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */ #define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */ -#define AOPOBJ_DATA_VALID 0x04 /* Object is intialized and data is valid */ +#define AOPOBJ_DATA_VALID 0x04 /* Object is initialized and data is valid */ #define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */ #define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */ #define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */ diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index cf29df69380b..096aebfe7f32 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -39,7 +39,7 @@ #define EINJ_PFX "EINJ: " #define SPIN_UNIT 100 /* 100ns */ -/* Firmware should respond within 1 miliseconds */ +/* Firmware should respond within 1 milliseconds */ #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) /* diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 5850d320404c..cf6db6b7662a 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -53,7 +53,7 @@ sizeof(struct acpi_table_erst))) #define SPIN_UNIT 100 /* 100ns */ -/* Firmware should respond within 1 miliseconds */ +/* Firmware should respond within 1 milliseconds */ #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) #define FIRMWARE_MAX_STALL 50 /* 50us */ diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index febb153b5a68..c423231b952b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -319,7 +319,7 @@ static int acpi_suspend_state_valid(suspend_state_t pm_state) } } -static struct platform_suspend_ops acpi_suspend_ops = { +static const struct platform_suspend_ops acpi_suspend_ops = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, @@ -347,7 +347,7 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state) * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has * been requested. */ -static struct platform_suspend_ops acpi_suspend_ops_old = { +static const struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, .prepare_late = acpi_pm_pre_suspend, @@ -506,7 +506,7 @@ static void acpi_pm_thaw(void) acpi_enable_all_runtime_gpes(); } -static struct platform_hibernation_ops acpi_hibernation_ops = { +static const struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, .pre_snapshot = acpi_pm_prepare, @@ -549,7 +549,7 @@ static int acpi_hibernation_begin_old(void) * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has * been requested. */ -static struct platform_hibernation_ops acpi_hibernation_ops_old = { +static const struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, .pre_snapshot = acpi_pm_pre_suspend, diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 5cd0228d2daa..15a0fde4b32a 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -260,7 +260,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd) vd->brightness->levels[request_level]); } -static struct backlight_ops acpi_backlight_ops = { +static const struct backlight_ops acpi_backlight_ops = { .get_brightness = acpi_video_get_brightness, .update_status = acpi_video_set_brightness, }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0a6a943b3779..a31fe96f7de6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2240,7 +2240,7 @@ int ata_dev_configure(struct ata_device *dev) if (id[ATA_ID_CFA_KEY_MGMT] & 1) ata_dev_printk(dev, KERN_WARNING, "supports DRM functions and may " - "not be fully accessable.\n"); + "not be fully accessible.\n"); snprintf(revbuf, 7, "CFA"); } else { snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); @@ -2248,7 +2248,7 @@ int ata_dev_configure(struct ata_device *dev) if (ata_id_has_tpm(id)) ata_dev_printk(dev, KERN_WARNING, "supports DRM functions and may " - "not be fully accessable.\n"); + "not be fully accessible.\n"); } dev->n_sectors = ata_id_n_sectors(id); diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index b777176ff494..e079cf29ed5d 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -370,7 +370,7 @@ static int __devinit vsc_sata_init_one(struct pci_dev *pdev, if (pci_resource_len(pdev, 0) == 0) return -ENODEV; - /* map IO regions and intialize host accordingly */ + /* map IO regions and initialize host accordingly */ rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h index 5042bb2dab15..f53a43ae2bbe 100644 --- a/drivers/atm/idt77252.h +++ b/drivers/atm/idt77252.h @@ -572,7 +572,7 @@ struct idt77252_dev #define SAR_STAT_TSQF 0x00001000 /* Transmit Status Queue full */ #define SAR_STAT_TMROF 0x00000800 /* Timer overflow */ #define SAR_STAT_PHYI 0x00000400 /* PHY device Interrupt flag */ -#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Comand Busy Flag */ +#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Command Busy Flag */ #define SAR_STAT_FBQ3A 0x00000100 /* Free Buffer Queue 3 Attention */ #define SAR_STAT_FBQ2A 0x00000080 /* Free Buffer Queue 2 Attention */ #define SAR_STAT_RSQF 0x00000040 /* Receive Status Queue full */ diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 729254053758..d80d51b62a1a 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -2063,7 +2063,7 @@ static int tx_init(struct atm_dev *dev) - UBR Table size is 4K - UBR wait queue is 4K since the table and wait queues are contiguous, all the bytes - can be initialized by one memeset. + can be initialized by one memeset. */ vcsize_sel = 0; @@ -2089,7 +2089,7 @@ static int tx_init(struct atm_dev *dev) - ABR Table size is 2K - ABR wait queue is 2K since the table and wait queues are contiguous, all the bytes - can be intialized by one memeset. + can be initialized by one memeset. */ i = ABR_SCHED_TABLE * iadev->memSize; writew((i >> 11) & 0xffff, iadev->seg_reg+ABR_SBPTR_BASE); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index e243bd49764b..000e7b2006f8 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -975,7 +975,7 @@ struct klist *bus_get_device_klist(struct bus_type *bus) EXPORT_SYMBOL_GPL(bus_get_device_klist); /* - * Yes, this forcably breaks the klist abstraction temporarily. It + * Yes, this forcibly breaks the klist abstraction temporarily. It * just wants to sort the klist, not change reference counts and * take/drop locks rapidly in the process. It does all this while * holding the lock for the list, so objects can't otherwise be diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 2a52270aeb30..83404973f97a 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -8,7 +8,7 @@ * * * The driver model core calls device_pm_add() when a device is registered. - * This will intialize the embedded device_pm_info object in the device + * This will initialize the embedded device_pm_info object in the device * and add it to the list of power-controlled devices. sysfs entries for * controlling device power management will also be added. * diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 008d4a00b50d..e1e38b11f48a 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1790,18 +1790,29 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) rc = rbd_bus_add_dev(rbd_dev); if (rc) - goto err_out_disk; + goto err_out_blkdev; + /* set up and announce blkdev mapping */ rc = rbd_init_disk(rbd_dev); if (rc) - goto err_out_blkdev; + goto err_out_bus; return count; +err_out_bus: + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + list_del_init(&rbd_dev->node); + mutex_unlock(&ctl_mutex); + + /* this will also clean up rest of rbd_dev stuff */ + + rbd_bus_del_dev(rbd_dev); + kfree(options); + kfree(mon_dev_name); + return rc; + err_out_blkdev: unregister_blkdev(rbd_dev->major, rbd_dev->name); -err_out_disk: - rbd_free_disk(rbd_dev); err_out_client: rbd_put_client(rbd_dev); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d4a7776f4b77..0f175a866ef0 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1047,15 +1047,6 @@ config NSC_GPIO pc8736x_gpio drivers. If those drivers are built as modules, this one will be too, named nsc_gpio -config CS5535_GPIO - tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" - depends on X86_32 - help - Give userspace access to the GPIO pins on the AMD CS5535 and - CS5536 Geode companion devices. - - If compiled as a module, it will be called cs5535_gpio. - config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN)" depends on BLOCK diff --git a/drivers/char/Makefile b/drivers/char/Makefile index fa0b824b7a65..1e9dffb33778 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -82,7 +82,6 @@ obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o -obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 794aacb715c1..d0387a84eec1 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -24,6 +24,7 @@ * warranty of any kind, whether express or implied. */ +#include <crypto/padlock.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/hw_random.h> @@ -34,7 +35,6 @@ #include <asm/i387.h> -#define PFX KBUILD_MODNAME ": " enum { @@ -81,8 +81,7 @@ static inline u32 xstore(u32 *addr, u32 edx_in) ts_state = irq_ts_save(); asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" - :"=m"(*addr), "=a"(eax_out) - :"D"(addr), "d"(edx_in)); + : "=m" (*addr), "=a" (eax_out), "+d" (edx_in), "+D" (addr)); irq_ts_restore(ts_state); return eax_out; @@ -90,8 +89,10 @@ static inline u32 xstore(u32 *addr, u32 edx_in) static int via_rng_data_present(struct hwrng *rng, int wait) { + char buf[16 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ + ((aligned(STACK_ALIGN))); + u32 *via_rng_datum = (u32 *)PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); u32 bytes_out; - u32 *via_rng_datum = (u32 *)(&rng->priv); int i; /* We choose the recommended 1-byte-per-instruction RNG rate, @@ -115,6 +116,7 @@ static int via_rng_data_present(struct hwrng *rng, int wait) break; udelay(10); } + rng->priv = *via_rng_datum; return bytes_out ? 1 : 0; } diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index d3d63be2cd37..1a9f5f6d6ac5 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -30,7 +30,7 @@ #define RAMOOPS_KERNMSG_HDR "====" -#define RECORD_SIZE 4096 +#define RECORD_SIZE 4096UL static ulong mem_address; module_param(mem_address, ulong, 0400); @@ -68,11 +68,16 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, char *buf, *buf_orig; struct timeval timestamp; + if (reason != KMSG_DUMP_OOPS && + reason != KMSG_DUMP_PANIC && + reason != KMSG_DUMP_KEXEC) + return; + /* Only dump oopses if dump_oops is set */ if (reason == KMSG_DUMP_OOPS && !dump_oops) return; - buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE)); + buf = cxt->virt_addr + (cxt->count * RECORD_SIZE); buf_orig = buf; memset(buf, '\0', RECORD_SIZE); @@ -83,8 +88,8 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, buf += res; hdr_size = buf - buf_orig; - l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - hdr_size)); - l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - hdr_size) - l2_cpy); + l2_cpy = min(l2, RECORD_SIZE - hdr_size); + l1_cpy = min(l1, RECORD_SIZE - hdr_size - l2_cpy); s2_start = l2 - l2_cpy; s1_start = l1 - l1_cpy; diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 7d279e578df5..c99305afa58a 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -857,7 +857,7 @@ static int mv_cra_hash_init(struct crypto_tfm *tfm, const char *base_hash_name, printk(KERN_WARNING MV_CESA "Base driver '%s' could not be loaded!\n", base_hash_name); - err = PTR_ERR(fallback_tfm); + err = PTR_ERR(base_hash); goto err_bad_base; } } diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 76141262ea1d..80dc094e78c6 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1542,7 +1542,7 @@ out: return err; } -static void __exit n2_unregister_algs(void) +static void __devexit n2_unregister_algs(void) { mutex_lock(&spu_lock); if (!--algs_registered) diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 799ca517c121..add2a1a72ba4 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -74,11 +74,9 @@ #define FLAGS_CBC BIT(1) #define FLAGS_GIV BIT(2) -#define FLAGS_NEW_KEY BIT(4) -#define FLAGS_NEW_IV BIT(5) -#define FLAGS_INIT BIT(6) -#define FLAGS_FAST BIT(7) -#define FLAGS_BUSY 8 +#define FLAGS_INIT BIT(4) +#define FLAGS_FAST BIT(5) +#define FLAGS_BUSY BIT(6) struct omap_aes_ctx { struct omap_aes_dev *dd; @@ -98,19 +96,18 @@ struct omap_aes_reqctx { struct omap_aes_dev { struct list_head list; unsigned long phys_base; - void __iomem *io_base; + void __iomem *io_base; struct clk *iclk; struct omap_aes_ctx *ctx; struct device *dev; unsigned long flags; + int err; - u32 *iv; - u32 ctrl; + spinlock_t lock; + struct crypto_queue queue; - spinlock_t lock; - struct crypto_queue queue; - - struct tasklet_struct task; + struct tasklet_struct done_task; + struct tasklet_struct queue_task; struct ablkcipher_request *req; size_t total; @@ -179,9 +176,13 @@ static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit) static int omap_aes_hw_init(struct omap_aes_dev *dd) { - int err = 0; - + /* + * clocks are enabled when request starts and disabled when finished. + * It may be long delays between requests. + * Device might go to off mode to save power. + */ clk_enable(dd->iclk); + if (!(dd->flags & FLAGS_INIT)) { /* is it necessary to reset before every operation? */ omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET, @@ -193,39 +194,26 @@ static int omap_aes_hw_init(struct omap_aes_dev *dd) __asm__ __volatile__("nop"); __asm__ __volatile__("nop"); - err = omap_aes_wait(dd, AES_REG_SYSSTATUS, - AES_REG_SYSSTATUS_RESETDONE); - if (!err) - dd->flags |= FLAGS_INIT; - } + if (omap_aes_wait(dd, AES_REG_SYSSTATUS, + AES_REG_SYSSTATUS_RESETDONE)) + return -ETIMEDOUT; - return err; -} + dd->flags |= FLAGS_INIT; + dd->err = 0; + } -static void omap_aes_hw_cleanup(struct omap_aes_dev *dd) -{ - clk_disable(dd->iclk); + return 0; } -static void omap_aes_write_ctrl(struct omap_aes_dev *dd) +static int omap_aes_write_ctrl(struct omap_aes_dev *dd) { unsigned int key32; - int i; + int i, err; u32 val, mask; - val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); - if (dd->flags & FLAGS_CBC) - val |= AES_REG_CTRL_CBC; - if (dd->flags & FLAGS_ENCRYPT) - val |= AES_REG_CTRL_DIRECTION; - - if (dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) && - !(dd->ctx->flags & FLAGS_NEW_KEY)) - goto out; - - /* only need to write control registers for new settings */ - - dd->ctrl = val; + err = omap_aes_hw_init(dd); + if (err) + return err; val = 0; if (dd->dma_lch_out >= 0) @@ -237,30 +225,43 @@ static void omap_aes_write_ctrl(struct omap_aes_dev *dd) omap_aes_write_mask(dd, AES_REG_MASK, val, mask); - pr_debug("Set key\n"); key32 = dd->ctx->keylen / sizeof(u32); - /* set a key */ + + /* it seems a key should always be set even if it has not changed */ for (i = 0; i < key32; i++) { omap_aes_write(dd, AES_REG_KEY(i), __le32_to_cpu(dd->ctx->key[i])); } - dd->ctx->flags &= ~FLAGS_NEW_KEY; - if (dd->flags & FLAGS_NEW_IV) { - pr_debug("Set IV\n"); - omap_aes_write_n(dd, AES_REG_IV(0), dd->iv, 4); - dd->flags &= ~FLAGS_NEW_IV; - } + if ((dd->flags & FLAGS_CBC) && dd->req->info) + omap_aes_write_n(dd, AES_REG_IV(0), dd->req->info, 4); + + val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); + if (dd->flags & FLAGS_CBC) + val |= AES_REG_CTRL_CBC; + if (dd->flags & FLAGS_ENCRYPT) + val |= AES_REG_CTRL_DIRECTION; mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION | AES_REG_CTRL_KEY_SIZE; - omap_aes_write_mask(dd, AES_REG_CTRL, dd->ctrl, mask); + omap_aes_write_mask(dd, AES_REG_CTRL, val, mask); -out: - /* start DMA or disable idle mode */ - omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, - AES_REG_MASK_START); + /* IN */ + omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + AES_REG_DATA, 0, 4); + + omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); + omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); + + /* OUT */ + omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + AES_REG_DATA, 0, 4); + + omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); + + return 0; } static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx) @@ -288,8 +289,16 @@ static void omap_aes_dma_callback(int lch, u16 ch_status, void *data) { struct omap_aes_dev *dd = data; - if (lch == dd->dma_lch_out) - tasklet_schedule(&dd->task); + if (ch_status != OMAP_DMA_BLOCK_IRQ) { + pr_err("omap-aes DMA error status: 0x%hx\n", ch_status); + dd->err = -EIO; + dd->flags &= ~FLAGS_INIT; /* request to re-initialize */ + } else if (lch == dd->dma_lch_in) { + return; + } + + /* dma_lch_out - completed */ + tasklet_schedule(&dd->done_task); } static int omap_aes_dma_init(struct omap_aes_dev *dd) @@ -339,18 +348,6 @@ static int omap_aes_dma_init(struct omap_aes_dev *dd) goto err_dma_out; } - omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4); - - omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + AES_REG_DATA, 0, 4); - - omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4); - return 0; err_dma_out: @@ -406,6 +403,11 @@ static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf, if (!count) return off; + /* + * buflen and total are AES_BLOCK_SIZE size aligned, + * so count should be also aligned + */ + sg_copy_buf(buf + off, *sg, *offset, count, out); off += count; @@ -461,7 +463,9 @@ static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in, omap_start_dma(dd->dma_lch_in); omap_start_dma(dd->dma_lch_out); - omap_aes_write_ctrl(dd); + /* start DMA or disable idle mode */ + omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START, + AES_REG_MASK_START); return 0; } @@ -488,8 +492,10 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) count = min(dd->total, sg_dma_len(dd->in_sg)); count = min(count, sg_dma_len(dd->out_sg)); - if (count != dd->total) + if (count != dd->total) { + pr_err("request length != buffer length\n"); return -EINVAL; + } pr_debug("fast\n"); @@ -525,23 +531,25 @@ static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd) dd->total -= count; - err = omap_aes_hw_init(dd); - err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count); + if (err) { + dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); + dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE); + } return err; } static void omap_aes_finish_req(struct omap_aes_dev *dd, int err) { - struct omap_aes_ctx *ctx; + struct ablkcipher_request *req = dd->req; pr_debug("err: %d\n", err); - ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req)); + clk_disable(dd->iclk); + dd->flags &= ~FLAGS_BUSY; - if (!dd->total) - dd->req->base.complete(&dd->req->base, err); + req->base.complete(&req->base, err); } static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) @@ -553,8 +561,6 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START); - omap_aes_hw_cleanup(dd); - omap_stop_dma(dd->dma_lch_in); omap_stop_dma(dd->dma_lch_out); @@ -574,40 +580,39 @@ static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd) } } - if (err || !dd->total) - omap_aes_finish_req(dd, err); - return err; } -static int omap_aes_handle_req(struct omap_aes_dev *dd) +static int omap_aes_handle_queue(struct omap_aes_dev *dd, + struct ablkcipher_request *req) { struct crypto_async_request *async_req, *backlog; struct omap_aes_ctx *ctx; struct omap_aes_reqctx *rctx; - struct ablkcipher_request *req; unsigned long flags; - - if (dd->total) - goto start; + int err, ret = 0; spin_lock_irqsave(&dd->lock, flags); + if (req) + ret = ablkcipher_enqueue_request(&dd->queue, req); + if (dd->flags & FLAGS_BUSY) { + spin_unlock_irqrestore(&dd->lock, flags); + return ret; + } backlog = crypto_get_backlog(&dd->queue); async_req = crypto_dequeue_request(&dd->queue); - if (!async_req) - clear_bit(FLAGS_BUSY, &dd->flags); + if (async_req) + dd->flags |= FLAGS_BUSY; spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) - return 0; + return ret; if (backlog) backlog->complete(backlog, -EINPROGRESS); req = ablkcipher_request_cast(async_req); - pr_debug("get new req\n"); - /* assign new request to device */ dd->req = req; dd->total = req->nbytes; @@ -621,27 +626,22 @@ static int omap_aes_handle_req(struct omap_aes_dev *dd) rctx->mode &= FLAGS_MODE_MASK; dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; - dd->iv = req->info; - if ((dd->flags & FLAGS_CBC) && dd->iv) - dd->flags |= FLAGS_NEW_IV; - else - dd->flags &= ~FLAGS_NEW_IV; - + dd->ctx = ctx; ctx->dd = dd; - if (dd->ctx != ctx) { - /* assign new context to device */ - dd->ctx = ctx; - ctx->flags |= FLAGS_NEW_KEY; - } - if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) - pr_err("request size is not exact amount of AES blocks\n"); + err = omap_aes_write_ctrl(dd); + if (!err) + err = omap_aes_crypt_dma_start(dd); + if (err) { + /* aes_task will not finish it, so do it here */ + omap_aes_finish_req(dd, err); + tasklet_schedule(&dd->queue_task); + } -start: - return omap_aes_crypt_dma_start(dd); + return ret; /* return ret, which is enqueue return value */ } -static void omap_aes_task(unsigned long data) +static void omap_aes_done_task(unsigned long data) { struct omap_aes_dev *dd = (struct omap_aes_dev *)data; int err; @@ -650,40 +650,50 @@ static void omap_aes_task(unsigned long data) err = omap_aes_crypt_dma_stop(dd); - err = omap_aes_handle_req(dd); + err = dd->err ? : err; + + if (dd->total && !err) { + err = omap_aes_crypt_dma_start(dd); + if (!err) + return; /* DMA started. Not fininishing. */ + } + + omap_aes_finish_req(dd, err); + omap_aes_handle_queue(dd, NULL); pr_debug("exit\n"); } +static void omap_aes_queue_task(unsigned long data) +{ + struct omap_aes_dev *dd = (struct omap_aes_dev *)data; + + omap_aes_handle_queue(dd, NULL); +} + static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) { struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx( crypto_ablkcipher_reqtfm(req)); struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req); struct omap_aes_dev *dd; - unsigned long flags; - int err; pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes, !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); + if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { + pr_err("request size is not exact amount of AES blocks\n"); + return -EINVAL; + } + dd = omap_aes_find_dev(ctx); if (!dd) return -ENODEV; rctx->mode = mode; - spin_lock_irqsave(&dd->lock, flags); - err = ablkcipher_enqueue_request(&dd->queue, req); - spin_unlock_irqrestore(&dd->lock, flags); - - if (!test_and_set_bit(FLAGS_BUSY, &dd->flags)) - omap_aes_handle_req(dd); - - pr_debug("exit\n"); - - return err; + return omap_aes_handle_queue(dd, req); } /* ********************** ALG API ************************************ */ @@ -701,7 +711,6 @@ static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, memcpy(ctx->key, key, keylen); ctx->keylen = keylen; - ctx->flags |= FLAGS_NEW_KEY; return 0; } @@ -750,7 +759,7 @@ static struct crypto_alg algs[] = { .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), - .cra_alignmask = 0, + .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, .cra_init = omap_aes_cra_init, @@ -770,7 +779,7 @@ static struct crypto_alg algs[] = { .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), - .cra_alignmask = 0, + .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, .cra_init = omap_aes_cra_init, @@ -849,7 +858,8 @@ static int omap_aes_probe(struct platform_device *pdev) (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR); clk_disable(dd->iclk); - tasklet_init(&dd->task, omap_aes_task, (unsigned long)dd); + tasklet_init(&dd->done_task, omap_aes_done_task, (unsigned long)dd); + tasklet_init(&dd->queue_task, omap_aes_queue_task, (unsigned long)dd); err = omap_aes_dma_init(dd); if (err) @@ -876,7 +886,8 @@ err_algs: crypto_unregister_alg(&algs[j]); omap_aes_dma_cleanup(dd); err_dma: - tasklet_kill(&dd->task); + tasklet_kill(&dd->done_task); + tasklet_kill(&dd->queue_task); iounmap(dd->io_base); err_io: clk_put(dd->iclk); @@ -903,7 +914,8 @@ static int omap_aes_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(algs); i++) crypto_unregister_alg(&algs[i]); - tasklet_kill(&dd->task); + tasklet_kill(&dd->done_task); + tasklet_kill(&dd->queue_task); omap_aes_dma_cleanup(dd); iounmap(dd->io_base); clk_put(dd->iclk); diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index a081c7c7d03f..2e71123516e0 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -72,10 +72,9 @@ #define DEFAULT_TIMEOUT_INTERVAL HZ -#define FLAGS_FIRST 0x0001 #define FLAGS_FINUP 0x0002 #define FLAGS_FINAL 0x0004 -#define FLAGS_FAST 0x0008 +#define FLAGS_SG 0x0008 #define FLAGS_SHA1 0x0010 #define FLAGS_DMA_ACTIVE 0x0020 #define FLAGS_OUTPUT_READY 0x0040 @@ -83,13 +82,17 @@ #define FLAGS_INIT 0x0100 #define FLAGS_CPU 0x0200 #define FLAGS_HMAC 0x0400 - -/* 3rd byte */ -#define FLAGS_BUSY 16 +#define FLAGS_ERROR 0x0800 +#define FLAGS_BUSY 0x1000 #define OP_UPDATE 1 #define OP_FINAL 2 +#define OMAP_ALIGN_MASK (sizeof(u32)-1) +#define OMAP_ALIGNED __attribute__((aligned(sizeof(u32)))) + +#define BUFLEN PAGE_SIZE + struct omap_sham_dev; struct omap_sham_reqctx { @@ -97,8 +100,8 @@ struct omap_sham_reqctx { unsigned long flags; unsigned long op; + u8 digest[SHA1_DIGEST_SIZE] OMAP_ALIGNED; size_t digcnt; - u8 *buffer; size_t bufcnt; size_t buflen; dma_addr_t dma_addr; @@ -107,6 +110,8 @@ struct omap_sham_reqctx { struct scatterlist *sg; unsigned int offset; /* offset in current sg */ unsigned int total; /* total request */ + + u8 buffer[0] OMAP_ALIGNED; }; struct omap_sham_hmac_ctx { @@ -136,6 +141,7 @@ struct omap_sham_dev { int irq; struct clk *iclk; spinlock_t lock; + int err; int dma; int dma_lch; struct tasklet_struct done_task; @@ -194,53 +200,68 @@ static inline int omap_sham_wait(struct omap_sham_dev *dd, u32 offset, u32 bit) static void omap_sham_copy_hash(struct ahash_request *req, int out) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + u32 *hash = (u32 *)ctx->digest; + int i; + + /* MD5 is almost unused. So copy sha1 size to reduce code */ + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) { + if (out) + hash[i] = omap_sham_read(ctx->dd, + SHA_REG_DIGEST(i)); + else + omap_sham_write(ctx->dd, + SHA_REG_DIGEST(i), hash[i]); + } +} + +static void omap_sham_copy_ready_hash(struct ahash_request *req) +{ + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + u32 *in = (u32 *)ctx->digest; u32 *hash = (u32 *)req->result; int i; + if (!hash) + return; + if (likely(ctx->flags & FLAGS_SHA1)) { /* SHA1 results are in big endian */ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) - if (out) - hash[i] = be32_to_cpu(omap_sham_read(ctx->dd, - SHA_REG_DIGEST(i))); - else - omap_sham_write(ctx->dd, SHA_REG_DIGEST(i), - cpu_to_be32(hash[i])); + hash[i] = be32_to_cpu(in[i]); } else { /* MD5 results are in little endian */ for (i = 0; i < MD5_DIGEST_SIZE / sizeof(u32); i++) - if (out) - hash[i] = le32_to_cpu(omap_sham_read(ctx->dd, - SHA_REG_DIGEST(i))); - else - omap_sham_write(ctx->dd, SHA_REG_DIGEST(i), - cpu_to_le32(hash[i])); + hash[i] = le32_to_cpu(in[i]); } } -static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, - int final, int dma) +static int omap_sham_hw_init(struct omap_sham_dev *dd) { - struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - u32 val = length << 5, mask; + clk_enable(dd->iclk); - if (unlikely(!ctx->digcnt)) { + if (!(dd->flags & FLAGS_INIT)) { + omap_sham_write_mask(dd, SHA_REG_MASK, + SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); - clk_enable(dd->iclk); + if (omap_sham_wait(dd, SHA_REG_SYSSTATUS, + SHA_REG_SYSSTATUS_RESETDONE)) + return -ETIMEDOUT; - if (!(dd->flags & FLAGS_INIT)) { - omap_sham_write_mask(dd, SHA_REG_MASK, - SHA_REG_MASK_SOFTRESET, SHA_REG_MASK_SOFTRESET); + dd->flags |= FLAGS_INIT; + dd->err = 0; + } - if (omap_sham_wait(dd, SHA_REG_SYSSTATUS, - SHA_REG_SYSSTATUS_RESETDONE)) - return -ETIMEDOUT; + return 0; +} - dd->flags |= FLAGS_INIT; - } - } else { +static void omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, + int final, int dma) +{ + struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); + u32 val = length << 5, mask; + + if (likely(ctx->digcnt)) omap_sham_write(dd, SHA_REG_DIGCNT, ctx->digcnt); - } omap_sham_write_mask(dd, SHA_REG_MASK, SHA_REG_MASK_IT_EN | (dma ? SHA_REG_MASK_DMA_EN : 0), @@ -260,29 +281,26 @@ static int omap_sham_write_ctrl(struct omap_sham_dev *dd, size_t length, SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH; omap_sham_write_mask(dd, SHA_REG_CTRL, val, mask); - - return 0; } static int omap_sham_xmit_cpu(struct omap_sham_dev *dd, const u8 *buf, size_t length, int final) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - int err, count, len32; + int count, len32; const u32 *buffer = (const u32 *)buf; dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n", ctx->digcnt, length, final); - err = omap_sham_write_ctrl(dd, length, final, 0); - if (err) - return err; + omap_sham_write_ctrl(dd, length, final, 0); + + /* should be non-zero before next lines to disable clocks later */ + ctx->digcnt += length; if (omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY)) return -ETIMEDOUT; - ctx->digcnt += length; - if (final) ctx->flags |= FLAGS_FINAL; /* catch last interrupt */ @@ -298,16 +316,11 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, size_t length, int final) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - int err, len32; + int len32; dev_dbg(dd->dev, "xmit_dma: digcnt: %d, length: %d, final: %d\n", ctx->digcnt, length, final); - /* flush cache entries related to our page */ - if (dma_addr == ctx->dma_addr) - dma_sync_single_for_device(dd->dev, dma_addr, length, - DMA_TO_DEVICE); - len32 = DIV_ROUND_UP(length, sizeof(u32)); omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32, @@ -317,9 +330,7 @@ static int omap_sham_xmit_dma(struct omap_sham_dev *dd, dma_addr_t dma_addr, omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); - err = omap_sham_write_ctrl(dd, length, final, 1); - if (err) - return err; + omap_sham_write_ctrl(dd, length, final, 1); ctx->digcnt += length; @@ -371,15 +382,29 @@ static size_t omap_sham_append_sg(struct omap_sham_reqctx *ctx) return 0; } +static int omap_sham_xmit_dma_map(struct omap_sham_dev *dd, + struct omap_sham_reqctx *ctx, + size_t length, int final) +{ + ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen, + DMA_TO_DEVICE); + if (dma_mapping_error(dd->dev, ctx->dma_addr)) { + dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen); + return -EINVAL; + } + + ctx->flags &= ~FLAGS_SG; + + /* next call does not fail... so no unmap in the case of error */ + return omap_sham_xmit_dma(dd, ctx->dma_addr, length, final); +} + static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); unsigned int final; size_t count; - if (!ctx->total) - return 0; - omap_sham_append_sg(ctx); final = (ctx->flags & FLAGS_FINUP) && !ctx->total; @@ -390,30 +415,68 @@ static int omap_sham_update_dma_slow(struct omap_sham_dev *dd) if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) { count = ctx->bufcnt; ctx->bufcnt = 0; - return omap_sham_xmit_dma(dd, ctx->dma_addr, count, final); + return omap_sham_xmit_dma_map(dd, ctx, count, final); } return 0; } -static int omap_sham_update_dma_fast(struct omap_sham_dev *dd) +/* Start address alignment */ +#define SG_AA(sg) (IS_ALIGNED(sg->offset, sizeof(u32))) +/* SHA1 block size alignment */ +#define SG_SA(sg) (IS_ALIGNED(sg->length, SHA1_MD5_BLOCK_SIZE)) + +static int omap_sham_update_dma_start(struct omap_sham_dev *dd) { struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); - unsigned int length; + unsigned int length, final, tail; + struct scatterlist *sg; - ctx->flags |= FLAGS_FAST; + if (!ctx->total) + return 0; + + if (ctx->bufcnt || ctx->offset) + return omap_sham_update_dma_slow(dd); + + dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n", + ctx->digcnt, ctx->bufcnt, ctx->total); + + sg = ctx->sg; - length = min(ctx->total, sg_dma_len(ctx->sg)); - ctx->total = length; + if (!SG_AA(sg)) + return omap_sham_update_dma_slow(dd); + + if (!sg_is_last(sg) && !SG_SA(sg)) + /* size is not SHA1_BLOCK_SIZE aligned */ + return omap_sham_update_dma_slow(dd); + + length = min(ctx->total, sg->length); + + if (sg_is_last(sg)) { + if (!(ctx->flags & FLAGS_FINUP)) { + /* not last sg must be SHA1_MD5_BLOCK_SIZE aligned */ + tail = length & (SHA1_MD5_BLOCK_SIZE - 1); + /* without finup() we need one block to close hash */ + if (!tail) + tail = SHA1_MD5_BLOCK_SIZE; + length -= tail; + } + } if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) { dev_err(dd->dev, "dma_map_sg error\n"); return -EINVAL; } + ctx->flags |= FLAGS_SG; + ctx->total -= length; + ctx->offset = length; /* offset where to start slow */ - return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, 1); + final = (ctx->flags & FLAGS_FINUP) && !ctx->total; + + /* next call does not fail... so no unmap in the case of error */ + return omap_sham_xmit_dma(dd, sg_dma_address(ctx->sg), length, final); } static int omap_sham_update_cpu(struct omap_sham_dev *dd) @@ -433,8 +496,17 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd) struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req); omap_stop_dma(dd->dma_lch); - if (ctx->flags & FLAGS_FAST) + if (ctx->flags & FLAGS_SG) { dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); + if (ctx->sg->length == ctx->offset) { + ctx->sg = sg_next(ctx->sg); + if (ctx->sg) + ctx->offset = 0; + } + } else { + dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, + DMA_TO_DEVICE); + } return 0; } @@ -454,14 +526,7 @@ static void omap_sham_cleanup(struct ahash_request *req) spin_unlock_irqrestore(&dd->lock, flags); if (ctx->digcnt) - clk_disable(dd->iclk); - - if (ctx->dma_addr) - dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen, - DMA_TO_DEVICE); - - if (ctx->buffer) - free_page((unsigned long)ctx->buffer); + omap_sham_copy_ready_hash(req); dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt); } @@ -489,8 +554,6 @@ static int omap_sham_init(struct ahash_request *req) ctx->flags = 0; - ctx->flags |= FLAGS_FIRST; - dev_dbg(dd->dev, "init: digest size: %d\n", crypto_ahash_digestsize(tfm)); @@ -499,21 +562,7 @@ static int omap_sham_init(struct ahash_request *req) ctx->bufcnt = 0; ctx->digcnt = 0; - - ctx->buflen = PAGE_SIZE; - ctx->buffer = (void *)__get_free_page( - (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC); - if (!ctx->buffer) - return -ENOMEM; - - ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, ctx->buflen, - DMA_TO_DEVICE); - if (dma_mapping_error(dd->dev, ctx->dma_addr)) { - dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen); - free_page((unsigned long)ctx->buffer); - return -EINVAL; - } + ctx->buflen = BUFLEN; if (tctx->flags & FLAGS_HMAC) { struct omap_sham_hmac_ctx *bctx = tctx->base; @@ -538,10 +587,8 @@ static int omap_sham_update_req(struct omap_sham_dev *dd) if (ctx->flags & FLAGS_CPU) err = omap_sham_update_cpu(dd); - else if (ctx->flags & FLAGS_FAST) - err = omap_sham_update_dma_fast(dd); else - err = omap_sham_update_dma_slow(dd); + err = omap_sham_update_dma_start(dd); /* wait for dma completion before can take more data */ dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n", err, ctx->digcnt); @@ -560,15 +607,12 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) use_dma = 0; if (use_dma) - err = omap_sham_xmit_dma(dd, ctx->dma_addr, ctx->bufcnt, 1); + err = omap_sham_xmit_dma_map(dd, ctx, ctx->bufcnt, 1); else err = omap_sham_xmit_cpu(dd, ctx->buffer, ctx->bufcnt, 1); ctx->bufcnt = 0; - if (err != -EINPROGRESS) - omap_sham_cleanup(req); - dev_dbg(dd->dev, "final_req: err: %d\n", err); return err; @@ -576,6 +620,7 @@ static int omap_sham_final_req(struct omap_sham_dev *dd) static int omap_sham_finish_req_hmac(struct ahash_request *req) { + struct omap_sham_reqctx *ctx = ahash_request_ctx(req); struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct omap_sham_hmac_ctx *bctx = tctx->base; int bs = crypto_shash_blocksize(bctx->shash); @@ -590,48 +635,56 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req) return crypto_shash_init(&desc.shash) ?: crypto_shash_update(&desc.shash, bctx->opad, bs) ?: - crypto_shash_finup(&desc.shash, req->result, ds, req->result); + crypto_shash_finup(&desc.shash, ctx->digest, ds, ctx->digest); } static void omap_sham_finish_req(struct ahash_request *req, int err) { struct omap_sham_reqctx *ctx = ahash_request_ctx(req); + struct omap_sham_dev *dd = ctx->dd; if (!err) { omap_sham_copy_hash(ctx->dd->req, 1); if (ctx->flags & FLAGS_HMAC) err = omap_sham_finish_req_hmac(req); + } else { + ctx->flags |= FLAGS_ERROR; } - if (ctx->flags & FLAGS_FINAL) + if ((ctx->flags & FLAGS_FINAL) || err) omap_sham_cleanup(req); - clear_bit(FLAGS_BUSY, &ctx->dd->flags); + clk_disable(dd->iclk); + dd->flags &= ~FLAGS_BUSY; if (req->base.complete) req->base.complete(&req->base, err); } -static int omap_sham_handle_queue(struct omap_sham_dev *dd) +static int omap_sham_handle_queue(struct omap_sham_dev *dd, + struct ahash_request *req) { struct crypto_async_request *async_req, *backlog; struct omap_sham_reqctx *ctx; - struct ahash_request *req, *prev_req; + struct ahash_request *prev_req; unsigned long flags; - int err = 0; - - if (test_and_set_bit(FLAGS_BUSY, &dd->flags)) - return 0; + int err = 0, ret = 0; spin_lock_irqsave(&dd->lock, flags); + if (req) + ret = ahash_enqueue_request(&dd->queue, req); + if (dd->flags & FLAGS_BUSY) { + spin_unlock_irqrestore(&dd->lock, flags); + return ret; + } backlog = crypto_get_backlog(&dd->queue); async_req = crypto_dequeue_request(&dd->queue); - if (!async_req) - clear_bit(FLAGS_BUSY, &dd->flags); + if (async_req) + dd->flags |= FLAGS_BUSY; spin_unlock_irqrestore(&dd->lock, flags); if (!async_req) - return 0; + return ret; if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -646,7 +699,22 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd) dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", ctx->op, req->nbytes); - if (req != prev_req && ctx->digcnt) + + err = omap_sham_hw_init(dd); + if (err) + goto err1; + + omap_set_dma_dest_params(dd->dma_lch, 0, + OMAP_DMA_AMODE_CONSTANT, + dd->phys_base + SHA_REG_DIN(0), 0, 16); + + omap_set_dma_dest_burst_mode(dd->dma_lch, + OMAP_DMA_DATA_BURST_16); + + omap_set_dma_src_burst_mode(dd->dma_lch, + OMAP_DMA_DATA_BURST_4); + + if (ctx->digcnt) /* request has changed - restore hash */ omap_sham_copy_hash(req, 0); @@ -658,7 +726,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd) } else if (ctx->op == OP_FINAL) { err = omap_sham_final_req(dd); } - +err1: if (err != -EINPROGRESS) { /* done_task will not finish it, so do it here */ omap_sham_finish_req(req, err); @@ -667,7 +735,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd) dev_dbg(dd->dev, "exit, err: %d\n", err); - return err; + return ret; } static int omap_sham_enqueue(struct ahash_request *req, unsigned int op) @@ -675,18 +743,10 @@ static int omap_sham_enqueue(struct ahash_request *req, unsigned int op) struct omap_sham_reqctx *ctx = ahash_request_ctx(req); struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm); struct omap_sham_dev *dd = tctx->dd; - unsigned long flags; - int err; ctx->op = op; - spin_lock_irqsave(&dd->lock, flags); - err = ahash_enqueue_request(&dd->queue, req); - spin_unlock_irqrestore(&dd->lock, flags); - - omap_sham_handle_queue(dd); - - return err; + return omap_sham_handle_queue(dd, req); } static int omap_sham_update(struct ahash_request *req) @@ -709,21 +769,13 @@ static int omap_sham_update(struct ahash_request *req) */ omap_sham_append_sg(ctx); return 0; - } else if (ctx->bufcnt + ctx->total <= 64) { + } else if (ctx->bufcnt + ctx->total <= SHA1_MD5_BLOCK_SIZE) { + /* + * faster to use CPU for short transfers + */ ctx->flags |= FLAGS_CPU; - } else if (!ctx->bufcnt && sg_is_last(ctx->sg)) { - /* may be can use faster functions */ - int aligned = IS_ALIGNED((u32)ctx->sg->offset, - sizeof(u32)); - - if (aligned && (ctx->flags & FLAGS_FIRST)) - /* digest: first and final */ - ctx->flags |= FLAGS_FAST; - - ctx->flags &= ~FLAGS_FIRST; } - } else if (ctx->bufcnt + ctx->total <= ctx->buflen) { - /* if not finaup -> not fast */ + } else if (ctx->bufcnt + ctx->total < ctx->buflen) { omap_sham_append_sg(ctx); return 0; } @@ -761,12 +813,14 @@ static int omap_sham_final(struct ahash_request *req) ctx->flags |= FLAGS_FINUP; - /* OMAP HW accel works only with buffers >= 9 */ - /* HMAC is always >= 9 because of ipad */ - if ((ctx->digcnt + ctx->bufcnt) < 9) - err = omap_sham_final_shash(req); - else if (ctx->bufcnt) - return omap_sham_enqueue(req, OP_FINAL); + if (!(ctx->flags & FLAGS_ERROR)) { + /* OMAP HW accel works only with buffers >= 9 */ + /* HMAC is always >= 9 because of ipad */ + if ((ctx->digcnt + ctx->bufcnt) < 9) + err = omap_sham_final_shash(req); + else if (ctx->bufcnt) + return omap_sham_enqueue(req, OP_FINAL); + } omap_sham_cleanup(req); @@ -836,6 +890,8 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm); const char *alg_name = crypto_tfm_alg_name(tfm); + pr_info("enter\n"); + /* Allocate a fallback and abort if it failed. */ tctx->fallback = crypto_alloc_shash(alg_name, 0, CRYPTO_ALG_NEED_FALLBACK); @@ -846,7 +902,7 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base) } crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct omap_sham_reqctx)); + sizeof(struct omap_sham_reqctx) + BUFLEN); if (alg_base) { struct omap_sham_hmac_ctx *bctx = tctx->base; @@ -932,7 +988,7 @@ static struct ahash_alg algs[] = { CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_sham_ctx), - .cra_alignmask = 0, + .cra_alignmask = OMAP_ALIGN_MASK, .cra_module = THIS_MODULE, .cra_init = omap_sham_cra_init, .cra_exit = omap_sham_cra_exit, @@ -956,7 +1012,7 @@ static struct ahash_alg algs[] = { .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_sham_ctx) + sizeof(struct omap_sham_hmac_ctx), - .cra_alignmask = 0, + .cra_alignmask = OMAP_ALIGN_MASK, .cra_module = THIS_MODULE, .cra_init = omap_sham_cra_sha1_init, .cra_exit = omap_sham_cra_exit, @@ -980,7 +1036,7 @@ static struct ahash_alg algs[] = { .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_sham_ctx) + sizeof(struct omap_sham_hmac_ctx), - .cra_alignmask = 0, + .cra_alignmask = OMAP_ALIGN_MASK, .cra_module = THIS_MODULE, .cra_init = omap_sham_cra_md5_init, .cra_exit = omap_sham_cra_exit, @@ -993,7 +1049,7 @@ static void omap_sham_done_task(unsigned long data) struct omap_sham_dev *dd = (struct omap_sham_dev *)data; struct ahash_request *req = dd->req; struct omap_sham_reqctx *ctx = ahash_request_ctx(req); - int ready = 1; + int ready = 0, err = 0; if (ctx->flags & FLAGS_OUTPUT_READY) { ctx->flags &= ~FLAGS_OUTPUT_READY; @@ -1003,15 +1059,18 @@ static void omap_sham_done_task(unsigned long data) if (dd->flags & FLAGS_DMA_ACTIVE) { dd->flags &= ~FLAGS_DMA_ACTIVE; omap_sham_update_dma_stop(dd); - omap_sham_update_dma_slow(dd); + if (!dd->err) + err = omap_sham_update_dma_start(dd); } - if (ready && !(dd->flags & FLAGS_DMA_ACTIVE)) { - dev_dbg(dd->dev, "update done\n"); + err = dd->err ? : err; + + if (err != -EINPROGRESS && (ready || err)) { + dev_dbg(dd->dev, "update done: err: %d\n", err); /* finish curent request */ - omap_sham_finish_req(req, 0); + omap_sham_finish_req(req, err); /* start new request */ - omap_sham_handle_queue(dd); + omap_sham_handle_queue(dd, NULL); } } @@ -1019,7 +1078,7 @@ static void omap_sham_queue_task(unsigned long data) { struct omap_sham_dev *dd = (struct omap_sham_dev *)data; - omap_sham_handle_queue(dd); + omap_sham_handle_queue(dd, NULL); } static irqreturn_t omap_sham_irq(int irq, void *dev_id) @@ -1041,6 +1100,7 @@ static irqreturn_t omap_sham_irq(int irq, void *dev_id) omap_sham_read(dd, SHA_REG_CTRL); ctx->flags |= FLAGS_OUTPUT_READY; + dd->err = 0; tasklet_schedule(&dd->done_task); return IRQ_HANDLED; @@ -1050,8 +1110,13 @@ static void omap_sham_dma_callback(int lch, u16 ch_status, void *data) { struct omap_sham_dev *dd = data; - if (likely(lch == dd->dma_lch)) - tasklet_schedule(&dd->done_task); + if (ch_status != OMAP_DMA_BLOCK_IRQ) { + pr_err("omap-sham DMA error status: 0x%hx\n", ch_status); + dd->err = -EIO; + dd->flags &= ~FLAGS_INIT; /* request to re-initialize */ + } + + tasklet_schedule(&dd->done_task); } static int omap_sham_dma_init(struct omap_sham_dev *dd) @@ -1066,15 +1131,6 @@ static int omap_sham_dma_init(struct omap_sham_dev *dd) dev_err(dd->dev, "Unable to request DMA channel\n"); return err; } - omap_set_dma_dest_params(dd->dma_lch, 0, - OMAP_DMA_AMODE_CONSTANT, - dd->phys_base + SHA_REG_DIN(0), 0, 16); - - omap_set_dma_dest_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_16); - - omap_set_dma_src_burst_mode(dd->dma_lch, - OMAP_DMA_DATA_BURST_4); return 0; } diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 8a515baa38f7..db33d300aa23 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -9,6 +9,7 @@ #include <crypto/algapi.h> #include <crypto/aes.h> +#include <crypto/padlock.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> @@ -21,7 +22,6 @@ #include <asm/byteorder.h> #include <asm/processor.h> #include <asm/i387.h> -#include "padlock.h" /* * Number of data blocks actually fetched for each xcrypt insn. diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c index d3a27e0119bc..adf075b6b9a8 100644 --- a/drivers/crypto/padlock-sha.c +++ b/drivers/crypto/padlock-sha.c @@ -13,6 +13,7 @@ */ #include <crypto/internal/hash.h> +#include <crypto/padlock.h> #include <crypto/sha.h> #include <linux/err.h> #include <linux/module.h> @@ -22,13 +23,6 @@ #include <linux/kernel.h> #include <linux/scatterlist.h> #include <asm/i387.h> -#include "padlock.h" - -#ifdef CONFIG_64BIT -#define STACK_ALIGN 16 -#else -#define STACK_ALIGN 4 -#endif struct padlock_sha_desc { struct shash_desc fallback; diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h deleted file mode 100644 index b728e4518bd1..000000000000 --- a/drivers/crypto/padlock.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Driver for VIA PadLock - * - * Copyright (c) 2004 Michal Ludvig <michal@logix.cz> - * - * 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. - * - */ - -#ifndef _CRYPTO_PADLOCK_H -#define _CRYPTO_PADLOCK_H - -#define PADLOCK_ALIGNMENT 16 - -#define PFX "padlock: " - -#define PADLOCK_CRA_PRIORITY 300 -#define PADLOCK_COMPOSITE_PRIORITY 400 - -#endif /* _CRYPTO_PADLOCK_H */ diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index b98c67664ae7..c461eda62411 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -110,8 +110,6 @@ static void unregister_dca_providers(void) /* at this point only one domain in the list is expected */ domain = list_first_entry(&dca_domains, struct dca_domain, node); - if (!domain) - return; list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) { list_del(&dca->node); diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 3109bd94bc4f..78266382797e 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1060,8 +1060,8 @@ static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data) * mid_setup_dma - Setup the DMA controller * @pdev: Controller PCI device structure * - * Initilize the DMA controller, channels, registers with DMA engine, - * ISR. Initilize DMA controller channels. + * Initialize the DMA controller, channels, registers with DMA engine, + * ISR. Initialize DMA controller channels. */ static int mid_setup_dma(struct pci_dev *pdev) { @@ -1217,7 +1217,7 @@ static void middma_shutdown(struct pci_dev *pdev) * @pdev: Controller PCI device structure * @id: pci device id structure * - * Initilize the PCI device, map BARs, query driver data. + * Initialize the PCI device, map BARs, query driver data. * Call setup_dma to complete contoller and chan initilzation */ static int __devinit intel_mid_dma_probe(struct pci_dev *pdev, diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h index 60e0d1c72dee..6f8b07131ec4 100644 --- a/drivers/edac/amd8131_edac.h +++ b/drivers/edac/amd8131_edac.h @@ -99,7 +99,7 @@ struct amd8131_dev_info { /* * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC - * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are + * Controller, and ATCA-6101 has two AMD8131 chipsets, so there are * four PCIX Bridges on ATCA-6101 altogether. * * These PCIX Bridges share the same PCI Device ID and are all of diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index c973004c002c..db1df59ae2b6 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -47,7 +47,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar) offset = address & ~PAGE_MASK; syndrome = (ar & 0x000000001fe00000ul) >> 21; - /* TODO: Decoding of the error addresss */ + /* TODO: Decoding of the error address */ edac_mc_handle_ce(mci, csrow->first_page + pfn, offset, syndrome, 0, chan, ""); } @@ -68,7 +68,7 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar) pfn = address >> PAGE_SHIFT; offset = address & ~PAGE_MASK; - /* TODO: Decoding of the error addresss */ + /* TODO: Decoding of the error address */ edac_mc_handle_ue(mci, csrow->first_page + pfn, offset, 0, ""); } diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index ff1eb7bb26c6..3d965347a673 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -259,7 +259,7 @@ enum scrub_type { * for single channel are 64 bits, for dual channel 128 * bits. * - * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memmory. + * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory. * Motherboards commonly drive two chip-select pins to * a memory stick. A single-ranked stick, will occupy * only one of those rows. The other will be unused. diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 362861c15779..81154ab296b6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1,6 +1,6 @@ /* Intel i7 core/Nehalem Memory Controller kernel module * - * This driver supports yhe memory controllers found on the Intel + * This driver supports the memory controllers found on the Intel * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx, * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield * and Westmere-EP. @@ -1271,7 +1271,7 @@ static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table) int i; /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses + * On Xeon 55xx, the Intel Quick Path Arch Generic Non-core pci buses * aren't announced by acpi. So, we need to use a legacy scan probing * to detect them */ @@ -1864,7 +1864,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) if (mce->mcgstatus & 1) i7core_check_error(mci); - /* Advice mcelog that the error were handled */ + /* Advise mcelog that the errors were handled */ return 1; } diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 070cea41b661..b9f0c20df1aa 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -873,7 +873,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1) } /** - * ppc4xx_edac_init_csrows - intialize driver instance rows + * ppc4xx_edac_init_csrows - initialize driver instance rows * @mci: A pointer to the EDAC memory controller instance * associated with the ibm,sdram-4xx-ddr2 controller for which * the csrows (i.e. banks/ranks) are being initialized. @@ -881,7 +881,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1) * currently set for the controller, from which bank width * and memory typ information is derived. * - * This routine intializes the virtual "chip select rows" associated + * This routine initializes the virtual "chip select rows" associated * with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2 * controller bank/rank is mapped to a row. * @@ -992,7 +992,7 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) } /** - * ppc4xx_edac_mc_init - intialize driver instance + * ppc4xx_edac_mc_init - initialize driver instance * @mci: A pointer to the EDAC memory controller instance being * initialized. * @op: A pointer to the OpenFirmware device tree node associated diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 082495bb08a7..664660e56335 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -118,7 +118,7 @@ config GPIO_SCH config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" - depends on GPIOLIB + depends on GPIOLIB && MFD_SUPPORT && PCI select MFD_CORE select MFD_VX855 help @@ -295,7 +295,7 @@ comment "PCI GPIO expanders:" config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" - depends on PCI && !CS5535_GPIO + depends on PCI && X86 && !CS5535_GPIO help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that can be used for quite a number of things. The CS5535/6 is found on @@ -333,6 +333,15 @@ config GPIO_PCH which is an IOH(Input/Output Hub) for x86 embedded processor. This driver can access PCH GPIO device. +config GPIO_ML_IOH + tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" + depends on PCI + help + ML7213 is companion chip for Intel Atom E6xx series. + This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output + Hub) which is for IVI(In-Vehicle Infotainment) use. + This driver can access the IOH's GPIO device. + config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM @@ -342,6 +351,7 @@ config GPIO_TIMBERDALE config GPIO_RDC321X tristate "RDC R-321x GPIO support" depends on PCI && GPIOLIB + select MFD_SUPPORT select MFD_CORE select MFD_RDC321X help diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 39bfd7a37650..3351cf87b0ed 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -41,3 +41,4 @@ obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o +obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c index 0871f78af593..33fc685cb385 100644 --- a/drivers/gpio/adp5588-gpio.c +++ b/drivers/gpio/adp5588-gpio.c @@ -146,9 +146,10 @@ static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off) return dev->irq_base + off; } -static void adp5588_irq_bus_lock(unsigned int irq) +static void adp5588_irq_bus_lock(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + mutex_lock(&dev->irq_lock); } @@ -160,9 +161,9 @@ static void adp5588_irq_bus_lock(unsigned int irq) * and unlocks the bus. */ -static void adp5588_irq_bus_sync_unlock(unsigned int irq) +static void adp5588_irq_bus_sync_unlock(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); int i; for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) @@ -175,31 +176,31 @@ static void adp5588_irq_bus_sync_unlock(unsigned int irq) mutex_unlock(&dev->irq_lock); } -static void adp5588_irq_mask(unsigned int irq) +static void adp5588_irq_mask(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); - unsigned gpio = irq - dev->irq_base; + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + unsigned gpio = d->irq - dev->irq_base; dev->irq_mask[ADP5588_BANK(gpio)] &= ~ADP5588_BIT(gpio); } -static void adp5588_irq_unmask(unsigned int irq) +static void adp5588_irq_unmask(struct irq_data *d) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); - unsigned gpio = irq - dev->irq_base; + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + unsigned gpio = d->irq - dev->irq_base; dev->irq_mask[ADP5588_BANK(gpio)] |= ADP5588_BIT(gpio); } -static int adp5588_irq_set_type(unsigned int irq, unsigned int type) +static int adp5588_irq_set_type(struct irq_data *d, unsigned int type) { - struct adp5588_gpio *dev = get_irq_chip_data(irq); - uint16_t gpio = irq - dev->irq_base; + struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); + uint16_t gpio = d->irq - dev->irq_base; unsigned bank, bit; if ((type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&dev->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -222,11 +223,11 @@ static int adp5588_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip adp5588_irq_chip = { .name = "adp5588", - .mask = adp5588_irq_mask, - .unmask = adp5588_irq_unmask, - .bus_lock = adp5588_irq_bus_lock, - .bus_sync_unlock = adp5588_irq_bus_sync_unlock, - .set_type = adp5588_irq_set_type, + .irq_mask = adp5588_irq_mask, + .irq_unmask = adp5588_irq_unmask, + .irq_bus_lock = adp5588_irq_bus_lock, + .irq_bus_sync_unlock = adp5588_irq_bus_sync_unlock, + .irq_set_type = adp5588_irq_set_type, }; static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf) diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index d3e55a0ae92b..815d98b2c1ba 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -15,6 +15,7 @@ #include <linux/gpio.h> #include <linux/io.h> #include <linux/cs5535.h> +#include <asm/msr.h> #define DRV_NAME "cs5535-gpio" #define GPIO_BAR 1 @@ -144,6 +145,57 @@ int cs5535_gpio_isset(unsigned offset, unsigned int reg) } EXPORT_SYMBOL_GPL(cs5535_gpio_isset); +int cs5535_gpio_set_irq(unsigned group, unsigned irq) +{ + uint32_t lo, hi; + + if (group > 7 || irq > 15) + return -EINVAL; + + rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi); + + lo &= ~(0xF << (group * 4)); + lo |= (irq & 0xF) << (group * 4); + + wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi); + return 0; +} +EXPORT_SYMBOL_GPL(cs5535_gpio_set_irq); + +void cs5535_gpio_setup_event(unsigned offset, int pair, int pme) +{ + struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; + uint32_t shift = (offset % 8) * 4; + unsigned long flags; + uint32_t val; + + if (offset >= 24) + offset = GPIO_MAP_W; + else if (offset >= 16) + offset = GPIO_MAP_Z; + else if (offset >= 8) + offset = GPIO_MAP_Y; + else + offset = GPIO_MAP_X; + + spin_lock_irqsave(&chip->lock, flags); + val = inl(chip->base + offset); + + /* Clear whatever was there before */ + val &= ~(0xF << shift); + + /* Set the new value */ + val |= ((pair & 7) << shift); + + /* Set the PME bit if this is a PME event */ + if (pme) + val |= (1 << (shift + 3)); + + outl(val, chip->base + offset); + spin_unlock_irqrestore(&chip->lock, flags); +} +EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event); + /* * Generic gpio_chip API support. */ diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 64db9dc3a275..d81cc748e77f 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -134,10 +134,10 @@ static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return lnw->irq_base + offset; } -static int lnw_irq_type(unsigned irq, unsigned type) +static int lnw_irq_type(struct irq_data *d, unsigned type) { - struct lnw_gpio *lnw = get_irq_chip_data(irq); - u32 gpio = irq - lnw->irq_base; + struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); + u32 gpio = d->irq - lnw->irq_base; unsigned long flags; u32 value; void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); @@ -162,19 +162,19 @@ static int lnw_irq_type(unsigned irq, unsigned type) return 0; } -static void lnw_irq_unmask(unsigned irq) +static void lnw_irq_unmask(struct irq_data *d) { } -static void lnw_irq_mask(unsigned irq) +static void lnw_irq_mask(struct irq_data *d) { } static struct irq_chip lnw_irqchip = { .name = "LNW-GPIO", - .mask = lnw_irq_mask, - .unmask = lnw_irq_unmask, - .set_type = lnw_irq_type, + .irq_mask = lnw_irq_mask, + .irq_unmask = lnw_irq_unmask, + .irq_set_type = lnw_irq_type, }; static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c index 9cad60f9e962..9e1d01f0071a 100644 --- a/drivers/gpio/max732x.c +++ b/drivers/gpio/max732x.c @@ -327,40 +327,40 @@ static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) return chip->irq_base + off; } -static void max732x_irq_mask(unsigned int irq) +static void max732x_irq_mask(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur &= ~(1 << (irq - chip->irq_base)); + chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base)); } -static void max732x_irq_unmask(unsigned int irq) +static void max732x_irq_unmask(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask_cur |= 1 << (irq - chip->irq_base); + chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base); } -static void max732x_irq_bus_lock(unsigned int irq) +static void max732x_irq_bus_lock(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); mutex_lock(&chip->irq_lock); chip->irq_mask_cur = chip->irq_mask; } -static void max732x_irq_bus_sync_unlock(unsigned int irq) +static void max732x_irq_bus_sync_unlock(struct irq_data *d) { - struct max732x_chip *chip = get_irq_chip_data(irq); + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); max732x_irq_update_mask(chip); mutex_unlock(&chip->irq_lock); } -static int max732x_irq_set_type(unsigned int irq, unsigned int type) +static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { - struct max732x_chip *chip = get_irq_chip_data(irq); - uint16_t off = irq - chip->irq_base; + struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t off = d->irq - chip->irq_base; uint16_t mask = 1 << off; if (!(mask & chip->dir_input)) { @@ -371,7 +371,7 @@ static int max732x_irq_set_type(unsigned int irq, unsigned int type) if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -390,11 +390,11 @@ static int max732x_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip max732x_irq_chip = { .name = "max732x", - .mask = max732x_irq_mask, - .unmask = max732x_irq_unmask, - .bus_lock = max732x_irq_bus_lock, - .bus_sync_unlock = max732x_irq_bus_sync_unlock, - .set_type = max732x_irq_set_type, + .irq_mask = max732x_irq_mask, + .irq_unmask = max732x_irq_unmask, + .irq_bus_lock = max732x_irq_bus_lock, + .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock, + .irq_set_type = max732x_irq_set_type, }; static uint8_t max732x_irq_pending(struct max732x_chip *chip) diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c new file mode 100644 index 000000000000..cead8e6ff345 --- /dev/null +++ b/drivers/gpio/ml_ioh_gpio.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * 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. + * + * 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/pci.h> +#include <linux/gpio.h> + +#define PCI_VENDOR_ID_ROHM 0x10DB + +struct ioh_reg_comn { + u32 ien; + u32 istatus; + u32 idisp; + u32 iclr; + u32 imask; + u32 imaskclr; + u32 po; + u32 pi; + u32 pm; + u32 im_0; + u32 im_1; + u32 reserved; +}; + +struct ioh_regs { + struct ioh_reg_comn regs[8]; + u32 reserve1[16]; + u32 ioh_sel_reg[4]; + u32 reserve2[11]; + u32 srst; +}; + +/** + * struct ioh_gpio_reg_data - The register store data. + * @po_reg: To store contents of PO register. + * @pm_reg: To store contents of PM register. + */ +struct ioh_gpio_reg_data { + u32 po_reg; + u32 pm_reg; +}; + +/** + * struct ioh_gpio - GPIO private data structure. + * @base: PCI base address of Memory mapped I/O register. + * @reg: Memory mapped IOH GPIO register list. + * @dev: Pointer to device structure. + * @gpio: Data for GPIO infrastructure. + * @ioh_gpio_reg: Memory mapped Register data is saved here + * when suspend. + * @ch: Indicate GPIO channel + */ +struct ioh_gpio { + void __iomem *base; + struct ioh_regs __iomem *reg; + struct device *dev; + struct gpio_chip gpio; + struct ioh_gpio_reg_data ioh_gpio_reg; + struct mutex lock; + int ch; +}; + +static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12}; + +static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) +{ + u32 reg_val; + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + + mutex_lock(&chip->lock); + reg_val = ioread32(&chip->reg->regs[chip->ch].po); + if (val) + reg_val |= (1 << nr); + else + reg_val &= ~(1 << nr); + + iowrite32(reg_val, &chip->reg->regs[chip->ch].po); + mutex_unlock(&chip->lock); +} + +static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + + return ioread32(&chip->reg->regs[chip->ch].pi) & (1 << nr); +} + +static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, + int val) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + u32 pm; + u32 reg_val; + + mutex_lock(&chip->lock); + pm = ioread32(&chip->reg->regs[chip->ch].pm) & + ((1 << num_ports[chip->ch]) - 1); + pm |= (1 << nr); + iowrite32(pm, &chip->reg->regs[chip->ch].pm); + + reg_val = ioread32(&chip->reg->regs[chip->ch].po); + if (val) + reg_val |= (1 << nr); + else + reg_val &= ~(1 << nr); + + mutex_unlock(&chip->lock); + + return 0; +} + +static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + u32 pm; + + mutex_lock(&chip->lock); + pm = ioread32(&chip->reg->regs[chip->ch].pm) & + ((1 << num_ports[chip->ch]) - 1); + pm &= ~(1 << nr); + iowrite32(pm, &chip->reg->regs[chip->ch].pm); + mutex_unlock(&chip->lock); + + return 0; +} + +/* + * Save register configuration and disable interrupts. + */ +static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) +{ + chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po); + chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm); +} + +/* + * This function restores the register configuration of the GPIO device. + */ +static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) +{ + /* to store contents of PO register */ + iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po); + /* to store contents of PM register */ + iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm); +} + +static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) +{ + struct gpio_chip *gpio = &chip->gpio; + + gpio->label = dev_name(chip->dev); + gpio->owner = THIS_MODULE; + gpio->direction_input = ioh_gpio_direction_input; + gpio->get = ioh_gpio_get; + gpio->direction_output = ioh_gpio_direction_output; + gpio->set = ioh_gpio_set; + gpio->dbg_show = NULL; + gpio->base = -1; + gpio->ngpio = num_port; + gpio->can_sleep = 0; +} + +static int __devinit ioh_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + int i; + struct ioh_gpio *chip; + void __iomem *base; + void __iomem *chip_save; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "%s : pci_enable_device failed", __func__); + goto err_pci_enable; + } + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + dev_err(&pdev->dev, "pci_request_regions failed-%d", ret); + goto err_request_regions; + } + + base = pci_iomap(pdev, 1, 0); + if (base == 0) { + dev_err(&pdev->dev, "%s : pci_iomap failed", __func__); + ret = -ENOMEM; + goto err_iomap; + } + + chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL); + if (chip_save == NULL) { + dev_err(&pdev->dev, "%s : kzalloc failed", __func__); + ret = -ENOMEM; + goto err_kzalloc; + } + + chip = chip_save; + for (i = 0; i < 8; i++, chip++) { + chip->dev = &pdev->dev; + chip->base = base; + chip->reg = chip->base; + chip->ch = i; + mutex_init(&chip->lock); + ioh_gpio_setup(chip, num_ports[i]); + ret = gpiochip_add(&chip->gpio); + if (ret) { + dev_err(&pdev->dev, "IOH gpio: Failed to register GPIO\n"); + goto err_gpiochip_add; + } + } + + chip = chip_save; + pci_set_drvdata(pdev, chip); + + return 0; + +err_gpiochip_add: + for (; i != 0; i--) { + chip--; + ret = gpiochip_remove(&chip->gpio); + if (ret) + dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i); + } + kfree(chip_save); + +err_kzalloc: + pci_iounmap(pdev, base); + +err_iomap: + pci_release_regions(pdev); + +err_request_regions: + pci_disable_device(pdev); + +err_pci_enable: + + dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret); + return ret; +} + +static void __devexit ioh_gpio_remove(struct pci_dev *pdev) +{ + int err; + int i; + struct ioh_gpio *chip = pci_get_drvdata(pdev); + void __iomem *chip_save; + + chip_save = chip; + for (i = 0; i < 8; i++, chip++) { + err = gpiochip_remove(&chip->gpio); + if (err) + dev_err(&pdev->dev, "Failed gpiochip_remove\n"); + } + + chip = chip_save; + pci_iounmap(pdev, chip->base); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(chip); +} + +#ifdef CONFIG_PM +static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state) +{ + s32 ret; + struct ioh_gpio *chip = pci_get_drvdata(pdev); + + ioh_gpio_save_reg_conf(chip); + ioh_gpio_restore_reg_conf(chip); + + ret = pci_save_state(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret); + return ret; + } + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_wake(pdev, PCI_D0, 1); + if (ret) + dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret); + + return 0; +} + +static int ioh_gpio_resume(struct pci_dev *pdev) +{ + s32 ret; + struct ioh_gpio *chip = pci_get_drvdata(pdev); + + ret = pci_enable_wake(pdev, PCI_D0, 0); + + pci_set_power_state(pdev, PCI_D0); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret); + return ret; + } + pci_restore_state(pdev); + + iowrite32(0x01, &chip->reg->srst); + iowrite32(0x00, &chip->reg->srst); + ioh_gpio_restore_reg_conf(chip); + + return 0; +} +#else +#define ioh_gpio_suspend NULL +#define ioh_gpio_resume NULL +#endif + +static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = { + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, + { 0, } +}; + +static struct pci_driver ioh_gpio_driver = { + .name = "ml_ioh_gpio", + .id_table = ioh_gpio_pcidev_id, + .probe = ioh_gpio_probe, + .remove = __devexit_p(ioh_gpio_remove), + .suspend = ioh_gpio_suspend, + .resume = ioh_gpio_resume +}; + +static int __init ioh_gpio_pci_init(void) +{ + return pci_register_driver(&ioh_gpio_driver); +} +module_init(ioh_gpio_pci_init); + +static void __exit ioh_gpio_pci_exit(void) +{ + pci_unregister_driver(&ioh_gpio_driver); +} +module_exit(ioh_gpio_pci_exit); + +MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 501866662e05..a261972f603d 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -228,30 +228,30 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) return chip->irq_base + off; } -static void pca953x_irq_mask(unsigned int irq) +static void pca953x_irq_mask(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (irq - chip->irq_base)); + chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); } -static void pca953x_irq_unmask(unsigned int irq) +static void pca953x_irq_unmask(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (irq - chip->irq_base); + chip->irq_mask |= 1 << (d->irq - chip->irq_base); } -static void pca953x_irq_bus_lock(unsigned int irq) +static void pca953x_irq_bus_lock(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); mutex_lock(&chip->irq_lock); } -static void pca953x_irq_bus_sync_unlock(unsigned int irq) +static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { - struct pca953x_chip *chip = get_irq_chip_data(irq); + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); uint16_t new_irqs; uint16_t level; @@ -268,15 +268,15 @@ static void pca953x_irq_bus_sync_unlock(unsigned int irq) mutex_unlock(&chip->irq_lock); } -static int pca953x_irq_set_type(unsigned int irq, unsigned int type) +static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { - struct pca953x_chip *chip = get_irq_chip_data(irq); - uint16_t level = irq - chip->irq_base; + struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + uint16_t level = d->irq - chip->irq_base; uint16_t mask = 1 << level; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", - irq, type); + d->irq, type); return -EINVAL; } @@ -295,11 +295,11 @@ static int pca953x_irq_set_type(unsigned int irq, unsigned int type) static struct irq_chip pca953x_irq_chip = { .name = "pca953x", - .mask = pca953x_irq_mask, - .unmask = pca953x_irq_unmask, - .bus_lock = pca953x_irq_bus_lock, - .bus_sync_unlock = pca953x_irq_bus_sync_unlock, - .set_type = pca953x_irq_set_type, + .irq_mask = pca953x_irq_mask, + .irq_unmask = pca953x_irq_unmask, + .irq_bus_lock = pca953x_irq_bus_lock, + .irq_bus_sync_unlock = pca953x_irq_bus_sync_unlock, + .irq_set_type = pca953x_irq_set_type, }; static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 5005990f751f..2975d22daffe 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -129,10 +129,10 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) /* * PL061 GPIO IRQ */ -static void pl061_irq_disable(unsigned irq) +static void pl061_irq_disable(struct irq_data *d) { - struct pl061_gpio *chip = get_irq_chip_data(irq); - int offset = irq - chip->irq_base; + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpioie; @@ -143,10 +143,10 @@ static void pl061_irq_disable(unsigned irq) spin_unlock_irqrestore(&chip->irq_lock, flags); } -static void pl061_irq_enable(unsigned irq) +static void pl061_irq_enable(struct irq_data *d) { - struct pl061_gpio *chip = get_irq_chip_data(irq); - int offset = irq - chip->irq_base; + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpioie; @@ -157,10 +157,10 @@ static void pl061_irq_enable(unsigned irq) spin_unlock_irqrestore(&chip->irq_lock, flags); } -static int pl061_irq_type(unsigned irq, unsigned trigger) +static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = get_irq_chip_data(irq); - int offset = irq - chip->irq_base; + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + int offset = d->irq - chip->irq_base; unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -203,9 +203,9 @@ static int pl061_irq_type(unsigned irq, unsigned trigger) static struct irq_chip pl061_irqchip = { .name = "GPIO", - .enable = pl061_irq_enable, - .disable = pl061_irq_disable, - .set_type = pl061_irq_type, + .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) @@ -214,7 +214,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) struct list_head *ptr; struct pl061_gpio *chip; - desc->chip->ack(irq); + desc->irq_data.chip->irq_ack(&desc->irq_data); list_for_each(ptr, chip_list) { unsigned long pending; int offset; @@ -229,7 +229,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) for_each_set_bit(offset, &pending, PL061_GPIO_NR) generic_handle_irq(pl061_to_irq(&chip->gc, offset)); } - desc->chip->unmask(irq); + desc->irq_data.chip->irq_unmask(&desc->irq_data); } static int pl061_probe(struct amba_device *dev, struct amba_id *id) diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c index 7c9e6a052c45..eb2901f8ab5e 100644 --- a/drivers/gpio/stmpe-gpio.c +++ b/drivers/gpio/stmpe-gpio.c @@ -122,10 +122,10 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type) +static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); - int offset = irq - stmpe_gpio->irq_base; + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - stmpe_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -145,16 +145,16 @@ static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type) return 0; } -static void stmpe_gpio_irq_lock(unsigned int irq) +static void stmpe_gpio_irq_lock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); mutex_lock(&stmpe_gpio->irq_lock); } -static void stmpe_gpio_irq_sync_unlock(unsigned int irq) +static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); struct stmpe *stmpe = stmpe_gpio->stmpe; int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); static const u8 regmap[] = { @@ -180,20 +180,20 @@ static void stmpe_gpio_irq_sync_unlock(unsigned int irq) mutex_unlock(&stmpe_gpio->irq_lock); } -static void stmpe_gpio_irq_mask(unsigned int irq) +static void stmpe_gpio_irq_mask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); - int offset = irq - stmpe_gpio->irq_base; + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - stmpe_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); stmpe_gpio->regs[REG_IE][regoffset] &= ~mask; } -static void stmpe_gpio_irq_unmask(unsigned int irq) +static void stmpe_gpio_irq_unmask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq); - int offset = irq - stmpe_gpio->irq_base; + struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - stmpe_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -202,11 +202,11 @@ static void stmpe_gpio_irq_unmask(unsigned int irq) static struct irq_chip stmpe_gpio_irq_chip = { .name = "stmpe-gpio", - .bus_lock = stmpe_gpio_irq_lock, - .bus_sync_unlock = stmpe_gpio_irq_sync_unlock, - .mask = stmpe_gpio_irq_mask, - .unmask = stmpe_gpio_irq_unmask, - .set_type = stmpe_gpio_irq_set_type, + .irq_bus_lock = stmpe_gpio_irq_lock, + .irq_bus_sync_unlock = stmpe_gpio_irq_sync_unlock, + .irq_mask = stmpe_gpio_irq_mask, + .irq_unmask = stmpe_gpio_irq_unmask, + .irq_set_type = stmpe_gpio_irq_set_type, }; static irqreturn_t stmpe_gpio_irq(int irq, void *dev) diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index 823559ab0e24..e60be0015c9b 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c @@ -304,36 +304,36 @@ static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return chip->irq_base + offset; } -static void sx150x_irq_mask(unsigned int irq) +static void sx150x_irq_mask(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n; chip = container_of(ic, struct sx150x_chip, irq_chip); - n = irq - chip->irq_base; + n = d->irq - chip->irq_base; sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); } -static void sx150x_irq_unmask(unsigned int irq) +static void sx150x_irq_unmask(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n; chip = container_of(ic, struct sx150x_chip, irq_chip); - n = irq - chip->irq_base; + n = d->irq - chip->irq_base; sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, chip->irq_sense >> (n * 2)); } -static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type) +static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n, val = 0; @@ -341,7 +341,7 @@ static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type) return -EINVAL; chip = container_of(ic, struct sx150x_chip, irq_chip); - n = irq - chip->irq_base; + n = d->irq - chip->irq_base; if (flow_type & IRQ_TYPE_EDGE_RISING) val |= 0x1; @@ -386,9 +386,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); } -static void sx150x_irq_bus_lock(unsigned int irq) +static void sx150x_irq_bus_lock(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; chip = container_of(ic, struct sx150x_chip, irq_chip); @@ -396,9 +396,9 @@ static void sx150x_irq_bus_lock(unsigned int irq) mutex_lock(&chip->lock); } -static void sx150x_irq_bus_sync_unlock(unsigned int irq) +static void sx150x_irq_bus_sync_unlock(struct irq_data *d) { - struct irq_chip *ic = get_irq_chip(irq); + struct irq_chip *ic = irq_data_get_irq_chip(d); struct sx150x_chip *chip; unsigned n; @@ -437,16 +437,16 @@ static void sx150x_init_chip(struct sx150x_chip *chip, if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; - chip->irq_chip.name = client->name; - chip->irq_chip.mask = sx150x_irq_mask; - chip->irq_chip.unmask = sx150x_irq_unmask; - chip->irq_chip.set_type = sx150x_irq_set_type; - chip->irq_chip.bus_lock = sx150x_irq_bus_lock; - chip->irq_chip.bus_sync_unlock = sx150x_irq_bus_sync_unlock; - chip->irq_summary = -1; - chip->irq_base = -1; - chip->irq_sense = 0; - chip->irq_set_type_pending = 0; + chip->irq_chip.name = client->name; + chip->irq_chip.irq_mask = sx150x_irq_mask; + chip->irq_chip.irq_unmask = sx150x_irq_unmask; + chip->irq_chip.irq_set_type = sx150x_irq_set_type; + chip->irq_chip.irq_bus_lock = sx150x_irq_bus_lock; + chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; + chip->irq_summary = -1; + chip->irq_base = -1; + chip->irq_sense = 0; + chip->irq_set_type_pending = 0; } static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c index 180d584454fb..27200af1a595 100644 --- a/drivers/gpio/tc3589x-gpio.c +++ b/drivers/gpio/tc3589x-gpio.c @@ -110,10 +110,10 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type) +static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); - int offset = irq - tc3589x_gpio->irq_base; + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tc3589x_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -137,16 +137,16 @@ static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type) return 0; } -static void tc3589x_gpio_irq_lock(unsigned int irq) +static void tc3589x_gpio_irq_lock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); mutex_lock(&tc3589x_gpio->irq_lock); } -static void tc3589x_gpio_irq_sync_unlock(unsigned int irq) +static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -172,20 +172,20 @@ static void tc3589x_gpio_irq_sync_unlock(unsigned int irq) mutex_unlock(&tc3589x_gpio->irq_lock); } -static void tc3589x_gpio_irq_mask(unsigned int irq) +static void tc3589x_gpio_irq_mask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); - int offset = irq - tc3589x_gpio->irq_base; + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tc3589x_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; } -static void tc3589x_gpio_irq_unmask(unsigned int irq) +static void tc3589x_gpio_irq_unmask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq); - int offset = irq - tc3589x_gpio->irq_base; + struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tc3589x_gpio->irq_base; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -194,11 +194,11 @@ static void tc3589x_gpio_irq_unmask(unsigned int irq) static struct irq_chip tc3589x_gpio_irq_chip = { .name = "tc3589x-gpio", - .bus_lock = tc3589x_gpio_irq_lock, - .bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, - .mask = tc3589x_gpio_irq_mask, - .unmask = tc3589x_gpio_irq_unmask, - .set_type = tc3589x_gpio_irq_set_type, + .irq_bus_lock = tc3589x_gpio_irq_lock, + .irq_bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, + .irq_mask = tc3589x_gpio_irq_mask, + .irq_unmask = tc3589x_gpio_irq_unmask, + .irq_set_type = tc3589x_gpio_irq_set_type, }; static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index 45293662e950..349131eb1ce0 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -109,10 +109,10 @@ static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset) /* * GPIO IRQ */ -static void timbgpio_irq_disable(unsigned irq) +static void timbgpio_irq_disable(struct irq_data *d) { - struct timbgpio *tgpio = get_irq_chip_data(irq); - int offset = irq - tgpio->irq_base; + struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tgpio->irq_base; unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); @@ -121,10 +121,10 @@ static void timbgpio_irq_disable(unsigned irq) spin_unlock_irqrestore(&tgpio->lock, flags); } -static void timbgpio_irq_enable(unsigned irq) +static void timbgpio_irq_enable(struct irq_data *d) { - struct timbgpio *tgpio = get_irq_chip_data(irq); - int offset = irq - tgpio->irq_base; + struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tgpio->irq_base; unsigned long flags; spin_lock_irqsave(&tgpio->lock, flags); @@ -133,10 +133,10 @@ static void timbgpio_irq_enable(unsigned irq) spin_unlock_irqrestore(&tgpio->lock, flags); } -static int timbgpio_irq_type(unsigned irq, unsigned trigger) +static int timbgpio_irq_type(struct irq_data *d, unsigned trigger) { - struct timbgpio *tgpio = get_irq_chip_data(irq); - int offset = irq - tgpio->irq_base; + struct timbgpio *tgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - tgpio->irq_base; unsigned long flags; u32 lvr, flr, bflr = 0; u32 ver; @@ -193,13 +193,13 @@ out: return ret; } -static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) +static void timbgpio_irq(struct irq_data *d, struct irq_desc *desc) { - struct timbgpio *tgpio = get_irq_data(irq); + struct timbgpio *tgpio = irq_data_get_irq_data(d); unsigned long ipr; int offset; - desc->chip->ack(irq); + desc->irq_data.chip->ack(irq_get_irq_data(d)); ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); @@ -217,9 +217,9 @@ static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) static struct irq_chip timbgpio_irqchip = { .name = "GPIO", - .enable = timbgpio_irq_enable, - .disable = timbgpio_irq_disable, - .set_type = timbgpio_irq_type, + .irq_enable = timbgpio_irq_enable, + .irq_disable = timbgpio_irq_disable, + .irq_set_type = timbgpio_irq_type, }; static int __devinit timbgpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c index b16c9a8c03f5..cffa3bd7ad3b 100644 --- a/drivers/gpio/vr41xx_giu.c +++ b/drivers/gpio/vr41xx_giu.c @@ -111,69 +111,69 @@ static inline u16 giu_clear(u16 offset, u16 clear) return data; } -static void ack_giuint_low(unsigned int irq) +static void ack_giuint_low(struct irq_data *d) { - giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } -static void mask_giuint_low(unsigned int irq) +static void mask_giuint_low(struct irq_data *d) { - giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } -static void mask_ack_giuint_low(unsigned int irq) +static void mask_ack_giuint_low(struct irq_data *d) { unsigned int pin; - pin = GPIO_PIN_OF_IRQ(irq); + pin = GPIO_PIN_OF_IRQ(d->irq); giu_clear(GIUINTENL, 1 << pin); giu_write(GIUINTSTATL, 1 << pin); } -static void unmask_giuint_low(unsigned int irq) +static void unmask_giuint_low(struct irq_data *d) { - giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } static struct irq_chip giuint_low_irq_chip = { .name = "GIUINTL", - .ack = ack_giuint_low, - .mask = mask_giuint_low, - .mask_ack = mask_ack_giuint_low, - .unmask = unmask_giuint_low, + .irq_ack = ack_giuint_low, + .irq_mask = mask_giuint_low, + .irq_mask_ack = mask_ack_giuint_low, + .irq_unmask = unmask_giuint_low, }; -static void ack_giuint_high(unsigned int irq) +static void ack_giuint_high(struct irq_data *d) { giu_write(GIUINTSTATH, - 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); } -static void mask_giuint_high(unsigned int irq) +static void mask_giuint_high(struct irq_data *d) { - giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); } -static void mask_ack_giuint_high(unsigned int irq) +static void mask_ack_giuint_high(struct irq_data *d) { unsigned int pin; - pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET; giu_clear(GIUINTENH, 1 << pin); giu_write(GIUINTSTATH, 1 << pin); } -static void unmask_giuint_high(unsigned int irq) +static void unmask_giuint_high(struct irq_data *d) { - giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); } static struct irq_chip giuint_high_irq_chip = { .name = "GIUINTH", - .ack = ack_giuint_high, - .mask = mask_giuint_high, - .mask_ack = mask_ack_giuint_high, - .unmask = unmask_giuint_high, + .irq_ack = ack_giuint_high, + .irq_mask = mask_giuint_high, + .irq_mask_ack = mask_ack_giuint_high, + .irq_unmask = unmask_giuint_high, }; static int giu_get_irq(unsigned int irq) diff --git a/drivers/gpio/wm8994-gpio.c b/drivers/gpio/wm8994-gpio.c index 618398e4ed8e..c822baacd8fc 100644 --- a/drivers/gpio/wm8994-gpio.c +++ b/drivers/gpio/wm8994-gpio.c @@ -35,6 +35,29 @@ static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip) return container_of(chip, struct wm8994_gpio, gpio_chip); } +static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); + struct wm8994 *wm8994 = wm8994_gpio->wm8994; + + switch (wm8994->type) { + case WM8958: + switch (offset) { + case 1: + case 2: + case 3: + case 4: + case 6: + return -EINVAL; + } + break; + default: + break; + } + + return 0; +} + static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset) { struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip); @@ -136,6 +159,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) static struct gpio_chip template_chip = { .label = "wm8994", .owner = THIS_MODULE, + .request = wm8994_gpio_request, .direction_input = wm8994_gpio_direction_in, .get = wm8994_gpio_get, .direction_output = wm8994_gpio_direction_out, diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index b14c81110575..d3a9c6e02477 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -59,7 +59,7 @@ static int nv40_set_intensity(struct backlight_device *bd) return 0; } -static struct backlight_ops nv40_bl_ops = { +static const struct backlight_ops nv40_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = nv40_get_intensity, .update_status = nv40_set_intensity, @@ -82,7 +82,7 @@ static int nv50_set_intensity(struct backlight_device *bd) return 0; } -static struct backlight_ops nv50_bl_ops = { +static const struct backlight_ops nv50_bl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = nv50_get_intensity, .update_status = nv50_set_intensity, diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index d3046559bf05..2aef5cd3acf5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1927,7 +1927,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * offset (8 bit): opcode * offset + 1 (16 bit): time * - * Sleep for "time" miliseconds. + * Sleep for "time" milliseconds. */ unsigned time = ROM16(bios->data[offset + 1]); @@ -1935,7 +1935,7 @@ init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) if (!iexec->execute) return 3; - BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n", + BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n", offset, time); msleep(time); diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 58a0cd02c0a2..04b269d14a59 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -1629,7 +1629,7 @@ typedef struct _GET_ENGINE_CLOCK_PARAMETERS typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS { USHORT usPrescale; //Ratio between Engine clock and I2C clock - USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID + USHORT usVRAMAddress; //Address in Frame Buffer where to pace raw EDID USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte UCHAR ucSlaveAddr; //Read from which slave diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index ffbc278647bf..24cca2f69dfc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -295,6 +295,23 @@ config HID_MONTEREY ---help--- Support for Monterey Genius KB29E. +config HID_MULTITOUCH + tristate "HID Multitouch panels" + depends on USB_HID + ---help--- + Generic support for HID multitouch panels. + + Say Y here if you have one of the following devices: + - Cypress TrueTouch panels + - Hanvon dual touch panels + - Pixcir dual touch panels + - 'Sensing Win7-TwoFinger' panel by GeneralTouch + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called hid-multitouch. + config HID_NTRIG tristate "N-Trig touch screen" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 6eae9a90b8dd..6efc2a0370ad 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MOSART) += hid-mosart.o +obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c index 375b50929a50..1ea066c55201 100644 --- a/drivers/hid/hid-cando.c +++ b/drivers/hid/hid-cando.c @@ -236,6 +236,8 @@ static const struct hid_device_id cando_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 261168607c91..d678cf3d33d5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1312,7 +1312,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, @@ -1324,6 +1326,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, @@ -1335,11 +1338,13 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, @@ -1422,6 +1427,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, @@ -1640,7 +1646,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f65cace77729..92a0d61a7379 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -140,7 +140,9 @@ #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 #define USB_VENDOR_ID_CANDO 0x2087 +#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 +#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 0x0a02 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01 @@ -186,6 +188,7 @@ #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 #define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1 +#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 #define USB_VENDOR_ID_DEALEXTREAME 0x10c5 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a @@ -236,6 +239,7 @@ #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc +#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001 #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 @@ -318,6 +322,9 @@ #define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000 #define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff +#define USB_VENDOR_ID_HANVON 0x20b3 +#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18 + #define USB_VENDOR_ID_HAPP 0x078b #define USB_DEVICE_ID_UGCI_DRIVING 0x0010 #define USB_DEVICE_ID_UGCI_FLYING 0x0020 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e60fdb88101f..7f552bfad32c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -290,6 +290,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel goto ignore; } + if (field->report_type == HID_FEATURE_REPORT) { + if (device->driver->feature_mapping) { + device->driver->feature_mapping(device, hidinput, field, + usage); + } + goto ignore; + } + if (device->driver->input_mapping) { int ret = device->driver->input_mapping(device, hidinput, field, usage, &bit, &max); @@ -839,7 +847,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) struct hid_input *hidinput = NULL; struct input_dev *input_dev; int i, j, k; - int max_report_type = HID_OUTPUT_REPORT; INIT_LIST_HEAD(&hid->inputs); @@ -856,10 +863,11 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) return -1; } - if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) - max_report_type = HID_INPUT_REPORT; + for (k = HID_INPUT_REPORT; k <= HID_FEATURE_REPORT; k++) { + if (k == HID_OUTPUT_REPORT && + hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) + continue; - for (k = HID_INPUT_REPORT; k <= max_report_type; k++) list_for_each_entry(report, &hid->report_enum[k].report_list, list) { if (!report->maxfield) @@ -912,6 +920,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) hidinput = NULL; } } + } if (hidinput && input_register_device(hidinput->input)) goto out_cleanup; diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c index 9fb050ce6f04..aed7ffe36283 100644 --- a/drivers/hid/hid-mosart.c +++ b/drivers/hid/hid-mosart.c @@ -257,6 +257,7 @@ static void mosart_remove(struct hid_device *hdev) static const struct hid_device_id mosart_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, { } }; MODULE_DEVICE_TABLE(hid, mosart_devices); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c new file mode 100644 index 000000000000..07d3183fdde5 --- /dev/null +++ b/drivers/hid/hid-multitouch.c @@ -0,0 +1,516 @@ +/* + * HID driver for multitouch panels + * + * Copyright (c) 2010-2011 Stephane Chatty <chatty@enac.fr> + * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com> + * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France + * + */ + +/* + * 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/hid.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/input/mt.h> +#include "usbhid/usbhid.h" + + +MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); +MODULE_DESCRIPTION("HID multitouch panels"); +MODULE_LICENSE("GPL"); + +#include "hid-ids.h" + +/* quirks to control the device */ +#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) +#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1) +#define MT_QUIRK_CYPRESS (1 << 2) +#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) +#define MT_QUIRK_VALID_IS_INRANGE (1 << 4) +#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) + +struct mt_slot { + __s32 x, y, p, w, h; + __s32 contactid; /* the device ContactID assigned to this slot */ + bool touch_state; /* is the touch valid? */ + bool seen_in_this_frame;/* has this slot been updated */ +}; + +struct mt_device { + struct mt_slot curdata; /* placeholder of incoming data */ + struct mt_class *mtclass; /* our mt device class */ + unsigned last_field_index; /* last field index of the report */ + unsigned last_slot_field; /* the last field of a slot */ + __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ + __u8 num_received; /* how many contacts we received */ + __u8 num_expected; /* expected last contact index */ + bool curvalid; /* is the current contact valid? */ + struct mt_slot slots[0]; /* first slot */ +}; + +struct mt_class { + __s32 name; /* MT_CLS */ + __s32 quirks; + __s32 sn_move; /* Signal/noise ratio for move events */ + __s32 sn_pressure; /* Signal/noise ratio for pressure events */ + __u8 maxcontacts; +}; + +/* classes of device behavior */ +#define MT_CLS_DEFAULT 1 +#define MT_CLS_DUAL1 2 +#define MT_CLS_DUAL2 3 +#define MT_CLS_CYPRESS 4 + +/* + * these device-dependent functions determine what slot corresponds + * to a valid contact that was just read. + */ + +static int cypress_compute_slot(struct mt_device *td) +{ + if (td->curdata.contactid != 0 || td->num_received == 0) + return td->curdata.contactid; + else + return -1; +} + +static int find_slot_from_contactid(struct mt_device *td) +{ + int i; + for (i = 0; i < td->mtclass->maxcontacts; ++i) { + if (td->slots[i].contactid == td->curdata.contactid && + td->slots[i].touch_state) + return i; + } + for (i = 0; i < td->mtclass->maxcontacts; ++i) { + if (!td->slots[i].seen_in_this_frame && + !td->slots[i].touch_state) + return i; + } + /* should not occurs. If this happens that means + * that the device sent more touches that it says + * in the report descriptor. It is ignored then. */ + return -1; +} + +struct mt_class mt_classes[] = { + { .name = MT_CLS_DEFAULT, + .quirks = MT_QUIRK_VALID_IS_INRANGE, + .maxcontacts = 10 }, + { .name = MT_CLS_DUAL1, + .quirks = MT_QUIRK_VALID_IS_INRANGE | + MT_QUIRK_SLOT_IS_CONTACTID, + .maxcontacts = 2 }, + { .name = MT_CLS_DUAL2, + .quirks = MT_QUIRK_VALID_IS_INRANGE | + MT_QUIRK_SLOT_IS_CONTACTNUMBER, + .maxcontacts = 2 }, + { .name = MT_CLS_CYPRESS, + .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | + MT_QUIRK_CYPRESS, + .maxcontacts = 10 }, + + { } +}; + +static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage) +{ + if (usage->hid == HID_DG_INPUTMODE) { + struct mt_device *td = hid_get_drvdata(hdev); + td->inputmode = field->report->id; + } +} + +static void set_abs(struct input_dev *input, unsigned int code, + struct hid_field *field, int snratio) +{ + int fmin = field->logical_minimum; + int fmax = field->logical_maximum; + int fuzz = snratio ? (fmax - fmin) / snratio : 0; + input_set_abs_params(input, code, fmin, fmax, fuzz, 0); +} + +static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + struct mt_device *td = hid_get_drvdata(hdev); + struct mt_class *cls = td->mtclass; + switch (usage->hid & HID_USAGE_PAGE) { + + case HID_UP_GENDESK: + switch (usage->hid) { + case HID_GD_X: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_X); + set_abs(hi->input, ABS_MT_POSITION_X, field, + cls->sn_move); + /* touchscreen emulation */ + set_abs(hi->input, ABS_X, field, cls->sn_move); + td->last_slot_field = usage->hid; + return 1; + case HID_GD_Y: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_POSITION_Y); + set_abs(hi->input, ABS_MT_POSITION_Y, field, + cls->sn_move); + /* touchscreen emulation */ + set_abs(hi->input, ABS_Y, field, cls->sn_move); + td->last_slot_field = usage->hid; + return 1; + } + return 0; + + case HID_UP_DIGITIZER: + switch (usage->hid) { + case HID_DG_INRANGE: + td->last_slot_field = usage->hid; + return 1; + case HID_DG_CONFIDENCE: + td->last_slot_field = usage->hid; + return 1; + case HID_DG_TIPSWITCH: + hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); + input_set_capability(hi->input, EV_KEY, BTN_TOUCH); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_CONTACTID: + input_mt_init_slots(hi->input, + td->mtclass->maxcontacts); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_WIDTH: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MAJOR); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_HEIGHT: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_TOUCH_MINOR); + field->logical_maximum = 1; + field->logical_minimum = 0; + set_abs(hi->input, ABS_MT_ORIENTATION, field, 0); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_TIPPRESSURE: + hid_map_usage(hi, usage, bit, max, + EV_ABS, ABS_MT_PRESSURE); + set_abs(hi->input, ABS_MT_PRESSURE, field, + cls->sn_pressure); + /* touchscreen emulation */ + set_abs(hi->input, ABS_PRESSURE, field, + cls->sn_pressure); + td->last_slot_field = usage->hid; + return 1; + case HID_DG_CONTACTCOUNT: + td->last_field_index = field->report->maxfield - 1; + return 1; + case HID_DG_CONTACTMAX: + /* we don't set td->last_slot_field as contactcount and + * contact max are global to the report */ + return -1; + } + /* let hid-input decide for the others */ + return 0; + + case 0xff000000: + /* we do not want to map these: no input-oriented meaning */ + return -1; + } + + return 0; +} + +static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if (usage->type == EV_KEY || usage->type == EV_ABS) + set_bit(usage->type, hi->input->evbit); + + return -1; +} + +static int mt_compute_slot(struct mt_device *td) +{ + __s32 quirks = td->mtclass->quirks; + + if (quirks & MT_QUIRK_SLOT_IS_CONTACTID) + return td->curdata.contactid; + + if (quirks & MT_QUIRK_CYPRESS) + return cypress_compute_slot(td); + + if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) + return td->num_received; + + return find_slot_from_contactid(td); +} + +/* + * this function is called when a whole contact has been processed, + * so that it can assign it to a slot and store the data there + */ +static void mt_complete_slot(struct mt_device *td) +{ + td->curdata.seen_in_this_frame = true; + if (td->curvalid) { + int slotnum = mt_compute_slot(td); + + if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) + td->slots[slotnum] = td->curdata; + } + td->num_received++; +} + + +/* + * this function is called when a whole packet has been received and processed, + * so that it can decide what to send to the input layer. + */ +static void mt_emit_event(struct mt_device *td, struct input_dev *input) +{ + int i; + + for (i = 0; i < td->mtclass->maxcontacts; ++i) { + struct mt_slot *s = &(td->slots[i]); + if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && + !s->seen_in_this_frame) { + s->touch_state = false; + } + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, + s->touch_state); + if (s->touch_state) { + input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); + input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h); + } + s->seen_in_this_frame = false; + + } + + input_mt_report_pointer_emulation(input, true); + input_sync(input); + td->num_received = 0; +} + + + +static int mt_event(struct hid_device *hid, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct mt_device *td = hid_get_drvdata(hid); + __s32 quirks = td->mtclass->quirks; + + if (hid->claimed & HID_CLAIMED_INPUT) { + switch (usage->hid) { + case HID_DG_INRANGE: + if (quirks & MT_QUIRK_VALID_IS_INRANGE) + td->curvalid = value; + break; + case HID_DG_TIPSWITCH: + if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) + td->curvalid = value; + td->curdata.touch_state = value; + break; + case HID_DG_CONFIDENCE: + if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE) + td->curvalid = value; + break; + case HID_DG_CONTACTID: + td->curdata.contactid = value; + break; + case HID_DG_TIPPRESSURE: + td->curdata.p = value; + break; + case HID_GD_X: + td->curdata.x = value; + break; + case HID_GD_Y: + td->curdata.y = value; + break; + case HID_DG_WIDTH: + td->curdata.w = value; + break; + case HID_DG_HEIGHT: + td->curdata.h = value; + break; + case HID_DG_CONTACTCOUNT: + /* + * Includes multi-packet support where subsequent + * packets are sent with zero contactcount. + */ + if (value) + td->num_expected = value; + break; + + default: + /* fallback to the generic hidinput handling */ + return 0; + } + + if (usage->hid == td->last_slot_field) + mt_complete_slot(td); + + if (field->index == td->last_field_index + && td->num_received >= td->num_expected) + mt_emit_event(td, field->hidinput->input); + + } + + /* we have handled the hidinput part, now remains hiddev */ + if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) + hid->hiddev_hid_event(hid, field, usage, value); + + return 1; +} + +static void mt_set_input_mode(struct hid_device *hdev) +{ + struct mt_device *td = hid_get_drvdata(hdev); + struct hid_report *r; + struct hid_report_enum *re; + + if (td->inputmode < 0) + return; + + re = &(hdev->report_enum[HID_FEATURE_REPORT]); + r = re->report_id_hash[td->inputmode]; + if (r) { + r->field[0]->value[0] = 0x02; + usbhid_submit_report(hdev, r, USB_DIR_OUT); + } +} + +static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret, i; + struct mt_device *td; + struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */ + + for (i = 0; mt_classes[i].name ; i++) { + if (id->driver_data == mt_classes[i].name) { + mtclass = &(mt_classes[i]); + break; + } + } + + /* This allows the driver to correctly support devices + * that emit events over several HID messages. + */ + hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; + + td = kzalloc(sizeof(struct mt_device) + + mtclass->maxcontacts * sizeof(struct mt_slot), + GFP_KERNEL); + if (!td) { + dev_err(&hdev->dev, "cannot allocate multitouch data\n"); + return -ENOMEM; + } + td->mtclass = mtclass; + td->inputmode = -1; + hid_set_drvdata(hdev, td); + + ret = hid_parse(hdev); + if (ret != 0) + goto fail; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) + goto fail; + + mt_set_input_mode(hdev); + + return 0; + +fail: + kfree(td); + return ret; +} + +#ifdef CONFIG_PM +static int mt_reset_resume(struct hid_device *hdev) +{ + mt_set_input_mode(hdev); + return 0; +} +#endif + +static void mt_remove(struct hid_device *hdev) +{ + struct mt_device *td = hid_get_drvdata(hdev); + hid_hw_stop(hdev); + kfree(td); + hid_set_drvdata(hdev, NULL); +} + +static const struct hid_device_id mt_devices[] = { + + /* Cypress panel */ + { .driver_data = MT_CLS_CYPRESS, + HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, + USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, + + /* GeneralTouch panel */ + { .driver_data = MT_CLS_DUAL2, + HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, + USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, + + /* PixCir-based panels */ + { .driver_data = MT_CLS_DUAL1, + HID_USB_DEVICE(USB_VENDOR_ID_HANVON, + USB_DEVICE_ID_HANVON_MULTITOUCH) }, + { .driver_data = MT_CLS_DUAL1, + HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, + + { } +}; +MODULE_DEVICE_TABLE(hid, mt_devices); + +static const struct hid_usage_id mt_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + +static struct hid_driver mt_driver = { + .name = "hid-multitouch", + .id_table = mt_devices, + .probe = mt_probe, + .remove = mt_remove, + .input_mapping = mt_input_mapping, + .input_mapped = mt_input_mapped, + .feature_mapping = mt_feature_mapping, + .usage_table = mt_grabbed_usages, + .event = mt_event, +#ifdef CONFIG_PM + .reset_resume = mt_reset_resume, +#endif +}; + +static int __init mt_init(void) +{ + return hid_register_driver(&mt_driver); +} + +static void __exit mt_exit(void) +{ + hid_unregister_driver(&mt_driver); +} + +module_init(mt_init); +module_exit(mt_exit); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 76b9a149c7df..9a94b643ccde 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -35,7 +35,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, { USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index bdc13d28b1ea..35f00dae3676 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -809,10 +809,10 @@ config SENSORS_DME1737 will be called dme1737. config SENSORS_EMC1403 - tristate "SMSC EMC1403 thermal sensor" + tristate "SMSC EMC1403/23 thermal sensor" depends on I2C help - If you say yes here you get support for the SMSC EMC1403 + If you say yes here you get support for the SMSC EMC1403/23 temperature monitoring chip. Threshold values can be configured using sysfs. diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 0727ad250793..9e234b981b83 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -20,7 +20,7 @@ * Alarms 16-bit map of active alarms * Analog Out 0..1250 mV output * - * Chassis Intrusion: clear CI latch with 'echo 1 > chassis_clear' + * Chassis Intrusion: clear CI latch with 'echo 0 > intrusion0_alarm' * * Test hardware: Intel SE440BX-2 desktop motherboard --Grant * @@ -476,13 +476,16 @@ static ssize_t set_aout(struct device *dev, static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); /* chassis_clear */ -static ssize_t chassis_clear(struct device *dev, +static ssize_t chassis_clear_legacy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); unsigned long val = simple_strtol(buf, NULL, 10); + dev_warn(dev, "Attribute chassis_clear is deprecated, " + "use intrusion0_alarm instead\n"); + if (val == 1) { i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); @@ -490,7 +493,29 @@ static ssize_t chassis_clear(struct device *dev, } return count; } -static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear); +static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear_legacy); + +static ssize_t chassis_clear(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adm9240_data *data = i2c_get_clientdata(client); + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(client, ADM9240_REG_CHASSIS_CLEAR, 0x80); + data->valid = 0; /* Force cache refresh */ + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "chassis intrusion latch cleared\n"); + + return count; +} +static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, show_alarm, + chassis_clear, 12); static struct attribute *adm9240_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, @@ -532,6 +557,7 @@ static struct attribute *adm9240_attributes[] = { &dev_attr_alarms.attr, &dev_attr_aout_output.attr, &dev_attr_chassis_clear.attr, + &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, &dev_attr_cpu0_vid.attr, NULL }; diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index aac85f3aed50..c42c5a69a664 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -4,7 +4,7 @@ This driver is based on the lm75 and other lm_sensors/hwmon drivers - Written by Steve Hardy <steve@linuxrealtime.co.uk> + Written by Steve Hardy <shardy@redhat.com> Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf @@ -271,7 +271,7 @@ static void __exit sensors_ads7828_exit(void) i2c_del_driver(&ads7828_driver); } -MODULE_AUTHOR("Steve Hardy <steve@linuxrealtime.co.uk>"); +MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); MODULE_DESCRIPTION("ADS7828 driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index e9a610bfd0cc..d9c592713919 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -77,12 +77,14 @@ enum chips { dme1737, sch5027, sch311x, sch5127 }; * in4 +12V * in5 VTR (+3.3V stby) * in6 Vbat + * in7 Vtrip (sch5127 only) * * --------------------------------------------------------------------- */ -/* Voltages (in) numbered 0-6 (ix) */ -#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) \ - : 0x94 + (ix)) +/* Voltages (in) numbered 0-7 (ix) */ +#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) : \ + (ix) < 7 ? 0x94 + (ix) : \ + 0x1f) #define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \ : 0x91 + (ix) * 2) #define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \ @@ -101,10 +103,11 @@ enum chips { dme1737, sch5027, sch311x, sch5127 }; * IN_TEMP_LSB(1) = [temp3, temp1] * IN_TEMP_LSB(2) = [in4, temp2] * IN_TEMP_LSB(3) = [in3, in0] - * IN_TEMP_LSB(4) = [in2, in1] */ + * IN_TEMP_LSB(4) = [in2, in1] + * IN_TEMP_LSB(5) = [res, in7] */ #define DME1737_REG_IN_TEMP_LSB(ix) (0x84 + (ix)) -static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0}; -static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4}; +static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0, 5}; +static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4, 4}; static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1}; static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0}; @@ -145,7 +148,7 @@ static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0}; #define DME1737_REG_ALARM1 0x41 #define DME1737_REG_ALARM2 0x42 #define DME1737_REG_ALARM3 0x83 -static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17}; +static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17, 18}; static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6}; static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; @@ -190,6 +193,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; #define HAS_PWM_MIN (1 << 4) /* bit 4 */ #define HAS_FAN(ix) (1 << ((ix) + 5)) /* bits 5-10 */ #define HAS_PWM(ix) (1 << ((ix) + 11)) /* bits 11-16 */ +#define HAS_IN7 (1 << 17) /* bit 17 */ /* --------------------------------------------------------------------- * Data structures and manipulation thereof @@ -213,9 +217,9 @@ struct dme1737_data { u32 has_features; /* Register values */ - u16 in[7]; - u8 in_min[7]; - u8 in_max[7]; + u16 in[8]; + u8 in_min[8]; + u8 in_max[8]; s16 temp[3]; s8 temp_min[3]; s8 temp_max[3]; @@ -247,7 +251,7 @@ static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300, static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300, 3300}; static const int IN_NOMINAL_SCH5127[] = {2500, 2250, 3300, 1125, 1125, 3300, - 3300}; + 3300, 1500}; #define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \ (type) == sch5027 ? IN_NOMINAL_SCH5027 : \ (type) == sch5127 ? IN_NOMINAL_SCH5127 : \ @@ -580,7 +584,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) { struct dme1737_data *data = dev_get_drvdata(dev); int ix; - u8 lsb[5]; + u8 lsb[6]; mutex_lock(&data->update_lock); @@ -603,6 +607,9 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* Voltage inputs are stored as 16 bit values even * though they have only 12 bits resolution. This is * to make it consistent with the temp inputs. */ + if (ix == 7 && !(data->has_features & HAS_IN7)) { + continue; + } data->in[ix] = dme1737_read(data, DME1737_REG_IN(ix)) << 8; data->in_min[ix] = dme1737_read(data, @@ -635,10 +642,16 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) * which the registers are read (MSB first, then LSB) is * important! */ for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) { + if (ix == 5 && !(data->has_features & HAS_IN7)) { + continue; + } lsb[ix] = dme1737_read(data, DME1737_REG_IN_TEMP_LSB(ix)); } for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) { + if (ix == 7 && !(data->has_features & HAS_IN7)) { + continue; + } data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] << DME1737_REG_IN_LSB_SHL[ix]) & 0xf0; } @@ -762,7 +775,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) /* --------------------------------------------------------------------- * Voltage sysfs attributes - * ix = [0-5] + * ix = [0-7] * --------------------------------------------------------------------- */ #define SYS_IN_INPUT 0 @@ -1439,7 +1452,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, * Sysfs device attribute defines and structs * --------------------------------------------------------------------- */ -/* Voltages 0-6 */ +/* Voltages 0-7 */ #define SENSOR_DEVICE_ATTR_IN(ix) \ static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \ @@ -1458,6 +1471,7 @@ SENSOR_DEVICE_ATTR_IN(3); SENSOR_DEVICE_ATTR_IN(4); SENSOR_DEVICE_ATTR_IN(5); SENSOR_DEVICE_ATTR_IN(6); +SENSOR_DEVICE_ATTR_IN(7); /* Temperatures 1-3 */ @@ -1576,7 +1590,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ * created unconditionally. The attributes that need modification of their * permissions are created read-only and write permissions are added or removed * on the fly when required */ -static struct attribute *dme1737_attr[] ={ +static struct attribute *dme1737_attr[] = { /* Voltages */ &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, @@ -1681,7 +1695,7 @@ static const struct attribute_group dme1737_zone3_group = { }; -/* The following struct holds temp zone hysteresis related attributes, which +/* The following struct holds temp zone hysteresis related attributes, which * are not available in all chips. The following chips support them: * DME1737, SCH311x */ static struct attribute *dme1737_zone_hyst_attr[] = { @@ -1695,6 +1709,21 @@ static const struct attribute_group dme1737_zone_hyst_group = { .attrs = dme1737_zone_hyst_attr, }; +/* The following struct holds voltage in7 related attributes, which + * are not available in all chips. The following chips support them: + * SCH5127 */ +static struct attribute *dme1737_in7_attr[] = { + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group dme1737_in7_group = { + .attrs = dme1737_in7_attr, +}; + /* The following structs hold the PWM attributes, some of which are optional. * Their creation depends on the chip configuration which is determined during * module load. */ @@ -1986,6 +2015,9 @@ static void dme1737_remove_files(struct device *dev) if (data->has_features & HAS_ZONE_HYST) { sysfs_remove_group(&dev->kobj, &dme1737_zone_hyst_group); } + if (data->has_features & HAS_IN7) { + sysfs_remove_group(&dev->kobj, &dme1737_in7_group); + } sysfs_remove_group(&dev->kobj, &dme1737_group); if (!data->client) { @@ -1999,43 +2031,58 @@ static int dme1737_create_files(struct device *dev) int err, ix; /* Create a name attribute for ISA devices */ - if (!data->client && - (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) { - goto exit; + if (!data->client) { + err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr); + if (err) { + goto exit; + } } /* Create standard sysfs attributes */ - if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) { + err = sysfs_create_group(&dev->kobj, &dme1737_group); + if (err) { goto exit_remove; } /* Create chip-dependent sysfs attributes */ - if ((data->has_features & HAS_TEMP_OFFSET) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_temp_offset_group))) { - goto exit_remove; + if (data->has_features & HAS_TEMP_OFFSET) { + err = sysfs_create_group(&dev->kobj, + &dme1737_temp_offset_group); + if (err) { + goto exit_remove; + } } - if ((data->has_features & HAS_VID) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_vid_group))) { - goto exit_remove; + if (data->has_features & HAS_VID) { + err = sysfs_create_group(&dev->kobj, &dme1737_vid_group); + if (err) { + goto exit_remove; + } } - if ((data->has_features & HAS_ZONE3) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_zone3_group))) { - goto exit_remove; + if (data->has_features & HAS_ZONE3) { + err = sysfs_create_group(&dev->kobj, &dme1737_zone3_group); + if (err) { + goto exit_remove; + } } - if ((data->has_features & HAS_ZONE_HYST) && - (err = sysfs_create_group(&dev->kobj, - &dme1737_zone_hyst_group))) { - goto exit_remove; + if (data->has_features & HAS_ZONE_HYST) { + err = sysfs_create_group(&dev->kobj, &dme1737_zone_hyst_group); + if (err) { + goto exit_remove; + } + } + if (data->has_features & HAS_IN7) { + err = sysfs_create_group(&dev->kobj, &dme1737_in7_group); + if (err) { + goto exit_remove; + } } /* Create fan sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { if (data->has_features & HAS_FAN(ix)) { - if ((err = sysfs_create_group(&dev->kobj, - &dme1737_fan_group[ix]))) { + err = sysfs_create_group(&dev->kobj, + &dme1737_fan_group[ix]); + if (err) { goto exit_remove; } } @@ -2044,14 +2091,17 @@ static int dme1737_create_files(struct device *dev) /* Create PWM sysfs attributes */ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { if (data->has_features & HAS_PWM(ix)) { - if ((err = sysfs_create_group(&dev->kobj, - &dme1737_pwm_group[ix]))) { + err = sysfs_create_group(&dev->kobj, + &dme1737_pwm_group[ix]); + if (err) { goto exit_remove; } - if ((data->has_features & HAS_PWM_MIN) && ix < 3 && - (err = sysfs_create_file(&dev->kobj, - dme1737_auto_pwm_min_attr[ix]))) { - goto exit_remove; + if ((data->has_features & HAS_PWM_MIN) && (ix < 3)) { + err = sysfs_create_file(&dev->kobj, + dme1737_auto_pwm_min_attr[ix]); + if (err) { + goto exit_remove; + } } } } @@ -2188,7 +2238,7 @@ static int dme1737_init_device(struct device *dev) data->has_features |= HAS_ZONE3; break; case sch5127: - data->has_features |= HAS_FAN(2) | HAS_PWM(2); + data->has_features |= HAS_FAN(2) | HAS_PWM(2) | HAS_IN7; break; default: break; @@ -2281,8 +2331,9 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) dme1737_sio_outb(sio_cip, 0x07, 0x0a); /* Get the base address of the runtime registers */ - if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | - dme1737_sio_inb(sio_cip, 0x61))) { + addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61); + if (!addr) { err = -ENODEV; goto exit; } @@ -2363,13 +2414,15 @@ static int dme1737_i2c_probe(struct i2c_client *client, mutex_init(&data->update_lock); /* Initialize the DME1737 chip */ - if ((err = dme1737_init_device(dev))) { + err = dme1737_init_device(dev); + if (err) { dev_err(dev, "Failed to initialize device.\n"); goto exit_kfree; } /* Create sysfs files */ - if ((err = dme1737_create_files(dev))) { + err = dme1737_create_files(dev); + if (err) { dev_err(dev, "Failed to create sysfs files.\n"); goto exit_kfree; } @@ -2446,8 +2499,9 @@ static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) dme1737_sio_outb(sio_cip, 0x07, 0x0a); /* Get the base address of the runtime registers */ - if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | - dme1737_sio_inb(sio_cip, 0x61))) { + base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61); + if (!base_addr) { pr_err("Base address not set\n"); err = -ENODEV; goto exit; @@ -2476,18 +2530,21 @@ static int __init dme1737_isa_device_add(unsigned short addr) if (err) goto exit; - if (!(pdev = platform_device_alloc("dme1737", addr))) { + pdev = platform_device_alloc("dme1737", addr); + if (!pdev) { pr_err("Failed to allocate device\n"); err = -ENOMEM; goto exit; } - if ((err = platform_device_add_resources(pdev, &res, 1))) { + err = platform_device_add_resources(pdev, &res, 1); + if (err) { pr_err("Failed to add device resource (err = %d)\n", err); goto exit_device_put; } - if ((err = platform_device_add(pdev))) { + err = platform_device_add(pdev); + if (err) { pr_err("Failed to add device (err = %d)\n", err); goto exit_device_put; } @@ -2514,11 +2571,12 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n", (unsigned short)res->start, (unsigned short)res->start + DME1737_EXTENT - 1); - err = -EBUSY; - goto exit; - } + err = -EBUSY; + goto exit; + } - if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) { + data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL); + if (!data) { err = -ENOMEM; goto exit_release_region; } @@ -2565,13 +2623,15 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev) data->type == sch5127 ? "SCH5127" : "SCH311x", data->addr); /* Initialize the chip */ - if ((err = dme1737_init_device(dev))) { + err = dme1737_init_device(dev); + if (err) { dev_err(dev, "Failed to initialize device.\n"); goto exit_kfree; } /* Create sysfs files */ - if ((err = dme1737_create_files(dev))) { + err = dme1737_create_files(dev); + if (err) { dev_err(dev, "Failed to create sysfs files.\n"); goto exit_kfree; } @@ -2628,7 +2688,8 @@ static int __init dme1737_init(void) int err; unsigned short addr; - if ((err = i2c_add_driver(&dme1737_i2c_driver))) { + err = i2c_add_driver(&dme1737_i2c_driver); + if (err) { goto exit; } @@ -2641,12 +2702,14 @@ static int __init dme1737_init(void) return 0; } - if ((err = platform_driver_register(&dme1737_isa_driver))) { + err = platform_driver_register(&dme1737_isa_driver); + if (err) { goto exit_del_i2c_driver; } /* Sets global pdev as a side effect */ - if ((err = dme1737_isa_device_add(addr))) { + err = dme1737_isa_device_add(addr); + if (err) { goto exit_del_isa_driver; } diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 8dee3f38fdfb..5dea9faa1656 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -269,23 +269,30 @@ static int emc1403_detect(struct i2c_client *client, struct i2c_board_info *info) { int id; - /* Check if thermal chip is SMSC and EMC1403 */ + /* Check if thermal chip is SMSC and EMC1403 or EMC1423 */ id = i2c_smbus_read_byte_data(client, THERMAL_SMSC_ID_REG); if (id != 0x5d) return -ENODEV; + id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); + switch (id) { + case 0x21: + strlcpy(info->type, "emc1403", I2C_NAME_SIZE); + break; + case 0x23: + strlcpy(info->type, "emc1423", I2C_NAME_SIZE); + break; /* Note: 0x25 is the 1404 which is very similar and this driver could be extended */ - id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); - if (id != 0x21) + default: return -ENODEV; + } id = i2c_smbus_read_byte_data(client, THERMAL_REVISION_REG); if (id != 0x01) return -ENODEV; - strlcpy(info->type, "emc1403", I2C_NAME_SIZE); return 0; } @@ -342,6 +349,7 @@ static const unsigned short emc1403_address_list[] = { static const struct i2c_device_id emc1403_idtable[] = { { "emc1403", 0 }, + { "emc1423", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, emc1403_idtable); diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index d4d4ca65d371..aa6d8b686f82 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -49,7 +49,6 @@ #include <linux/kref.h> /* Addresses to scan */ -static DEFINE_MUTEX(watchdog_mutex); static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; /* Insmod parameters */ @@ -850,7 +849,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf, static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - static struct watchdog_info ident = { + struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_CARDRESET, .identity = "FSC watchdog" @@ -858,7 +857,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar int i, ret = 0; struct fschmd_data *data = filp->private_data; - mutex_lock(&watchdog_mutex); switch (cmd) { case WDIOC_GETSUPPORT: ident.firmware_version = data->revision; @@ -915,7 +913,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long ar default: ret = -ENOTTY; } - mutex_unlock(&watchdog_mutex); return ret; } diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index a428a9264195..316b64823f7b 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -38,6 +38,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -1570,26 +1572,25 @@ static int __init it87_find(unsigned short *address, case 0xffff: /* No device at all */ goto exit; default: - pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n", - chip_type); + pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type); goto exit; } superio_select(PME); if (!(superio_inb(IT87_ACT_REG) & 0x01)) { - pr_info("it87: Device not activated, skipping\n"); + pr_info("Device not activated, skipping\n"); goto exit; } *address = superio_inw(IT87_BASE_REG) & ~(IT87_EXTENT - 1); if (*address == 0) { - pr_info("it87: Base address not set, skipping\n"); + pr_info("Base address not set, skipping\n"); goto exit; } err = 0; sio_data->revision = superio_inb(DEVREV) & 0x0f; - pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n", + pr_info("Found IT%04xF chip at 0x%x, revision %d\n", chip_type, *address, sio_data->revision); /* in8 (Vbat) is always internal */ @@ -1615,7 +1616,7 @@ static int __init it87_find(unsigned short *address, } else { /* We need at least 4 VID pins */ if (reg & 0x0f) { - pr_info("it87: VID is disabled (pins used for GPIO)\n"); + pr_info("VID is disabled (pins used for GPIO)\n"); sio_data->skip_vid = 1; } } @@ -1651,7 +1652,7 @@ static int __init it87_find(unsigned short *address, if (sio_data->type == it8720 && !(reg & (1 << 1))) { reg |= (1 << 1); superio_outb(IT87_SIO_PINX2_REG, reg); - pr_notice("it87: Routing internal VCCH to in7\n"); + pr_notice("Routing internal VCCH to in7\n"); } if (reg & (1 << 0)) sio_data->internal |= (1 << 0); @@ -1661,7 +1662,7 @@ static int __init it87_find(unsigned short *address, sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; } if (sio_data->beep_pin) - pr_info("it87: Beeping is supported\n"); + pr_info("Beeping is supported\n"); /* Disable specific features based on DMI strings */ board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); @@ -1675,8 +1676,7 @@ static int __init it87_find(unsigned short *address, the PWM2 duty cycle, so we disable it. I use the board name string as the trigger in case the same board is ever used in other systems. */ - pr_info("it87: Disabling pwm2 due to " - "hardware constraints\n"); + pr_info("Disabling pwm2 due to hardware constraints\n"); sio_data->skip_pwm = (1 << 1); } } @@ -2189,28 +2189,26 @@ static int __init it87_device_add(unsigned short address, pdev = platform_device_alloc(DRVNAME, address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct it87_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 72ff2c4e757d..4cb24eafe318 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -19,6 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -858,7 +860,7 @@ static int __init lm78_isa_found(unsigned short address) * individually for the probing phase. */ for (port = address; port < address + LM78_EXTENT; port++) { if (!request_region(port, 1, "lm78")) { - pr_debug("lm78: Failed to request port 0x%x\n", port); + pr_debug("Failed to request port 0x%x\n", port); goto release; } } @@ -920,7 +922,7 @@ static int __init lm78_isa_found(unsigned short address) found = 1; if (found) - pr_info("lm78: Found an %s chip at %#x\n", + pr_info("Found an %s chip at %#x\n", val & 0x80 ? "LM79" : "LM78", (int)address); release: @@ -942,21 +944,19 @@ static int __init lm78_isa_device_add(unsigned short address) pdev = platform_device_alloc("lm78", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "lm78: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "lm78: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "lm78: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 68e69a49633c..3d99b8854d7c 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -33,6 +33,8 @@ * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -1031,16 +1033,15 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses val = superio_inb(sioaddr, ACT); if (!(val & 0x01)) { - printk(KERN_INFO "pc87360: Device 0x%02x not " - "activated\n", logdev[i]); + pr_info("Device 0x%02x not activated\n", logdev[i]); continue; } val = (superio_inb(sioaddr, BASE) << 8) | superio_inb(sioaddr, BASE + 1); if (!val) { - printk(KERN_INFO "pc87360: Base address not set for " - "device 0x%02x\n", logdev[i]); + pr_info("Base address not set for device 0x%02x\n", + logdev[i]); continue; } @@ -1050,17 +1051,15 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses confreg[0] = superio_inb(sioaddr, 0xF0); confreg[1] = superio_inb(sioaddr, 0xF1); -#ifdef DEBUG - printk(KERN_DEBUG "pc87360: Fan 1: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>2)&1, - (confreg[0]>>3)&1, (confreg[0]>>4)&1); - printk(KERN_DEBUG "pc87360: Fan 2: mon=%d " - "ctrl=%d inv=%d\n", (confreg[0]>>5)&1, - (confreg[0]>>6)&1, (confreg[0]>>7)&1); - printk(KERN_DEBUG "pc87360: Fan 3: mon=%d " - "ctrl=%d inv=%d\n", confreg[1]&1, - (confreg[1]>>1)&1, (confreg[1]>>2)&1); -#endif + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1, + (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1, + (confreg[0] >> 4) & 1); + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2, + (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1, + (confreg[0] >> 7) & 1); + pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3, + confreg[1] & 1, (confreg[1] >> 1) & 1, + (confreg[1] >> 2) & 1); } else if (i==1) { /* Voltages */ /* Are we using thermistors? */ if (*devid == 0xE9) { /* PC87366 */ @@ -1071,14 +1070,12 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses confreg[3] = superio_inb(sioaddr, 0x25); if (confreg[2] & 0x40) { - printk(KERN_INFO "pc87360: Using " - "thermistors for temperature " - "monitoring\n"); + pr_info("Using thermistors for " + "temperature monitoring\n"); } if (confreg[3] & 0xE0) { - printk(KERN_INFO "pc87360: VID " - "inputs routed (mode %u)\n", - confreg[3] >> 5); + pr_info("VID inputs routed (mode %u)\n", + confreg[3] >> 5); } } } @@ -1616,7 +1613,7 @@ static int __init pc87360_device_add(unsigned short address) pdev = platform_device_alloc("pc87360", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "pc87360: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } @@ -1639,15 +1636,13 @@ static int __init pc87360_device_add(unsigned short address) err = platform_device_add_resources(pdev, res, res_count); if (err) { - printk(KERN_ERR "pc87360: Device resources addition failed " - "(%d)\n", err); + pr_err("Device resources addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "pc87360: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } @@ -1666,8 +1661,7 @@ static int __init pc87360_init(void) if (pc87360_find(0x2e, &devid, extra_isa) && pc87360_find(0x4e, &devid, extra_isa)) { - printk(KERN_WARNING "pc87360: PC8736x not detected, " - "module not inserted.\n"); + pr_warn("PC8736x not detected, module not inserted\n"); return -ENODEV; } @@ -1680,8 +1674,7 @@ static int __init pc87360_init(void) } if (address == 0x0000) { - printk(KERN_WARNING "pc87360: No active logical device, " - "module not inserted.\n"); + pr_warn("No active logical device, module not inserted\n"); return -ENODEV; } diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 9ec4daaf6ca6..8da2181630b1 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -22,6 +22,8 @@ * mode, and voltages aren't supported at all. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -1077,7 +1079,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev) data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL); if (!data) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Out of memory\n"); + pr_err("Out of memory\n"); goto exit; } @@ -1196,28 +1198,26 @@ static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) pdev = platform_device_alloc(DRVNAME, res[0].start); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, res, res_count); if (err) { - printk(KERN_ERR DRVNAME ": Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add_data(pdev, sio_data, sizeof(struct pc87427_sio_data)); if (err) { - printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); + pr_err("Platform data allocation failed\n"); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } @@ -1249,23 +1249,23 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data) val = superio_inb(sioaddr, SIOREG_ACT); if (!(val & 0x01)) { - printk(KERN_INFO DRVNAME ": Logical device 0x%02x " - "not activated\n", logdev[i]); + pr_info("Logical device 0x%02x not activated\n", + logdev[i]); continue; } val = superio_inb(sioaddr, SIOREG_MAP); if (val & 0x01) { - printk(KERN_WARNING DRVNAME ": Logical device 0x%02x " - "is memory-mapped, can't use\n", logdev[i]); + pr_warn("Logical device 0x%02x is memory-mapped, " + "can't use\n", logdev[i]); continue; } val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8) | superio_inb(sioaddr, SIOREG_IOBASE + 1); if (!val) { - printk(KERN_INFO DRVNAME ": I/O base address not set " - "for logical device 0x%02x\n", logdev[i]); + pr_info("I/O base address not set for logical device " + "0x%02x\n", logdev[i]); continue; } sio_data->address[i] = val; diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 13e8d218e495..25e91665a0a2 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -689,6 +689,13 @@ static int __devexit via686a_remove(struct platform_device *pdev) return 0; } +static void via686a_update_fan_div(struct via686a_data *data) +{ + int reg = via686a_read_value(data, VIA686A_REG_FANDIV); + data->fan_div[0] = (reg >> 4) & 0x03; + data->fan_div[1] = reg >> 6; +} + static void __devinit via686a_init_device(struct via686a_data *data) { u8 reg; @@ -702,6 +709,9 @@ static void __devinit via686a_init_device(struct via686a_data *data) via686a_write_value(data, VIA686A_REG_TEMP_MODE, (reg & ~VIA686A_TEMP_MODE_MASK) | VIA686A_TEMP_MODE_CONTINUOUS); + + /* Pre-read fan clock divisor values */ + via686a_update_fan_div(data); } static struct via686a_data *via686a_update_device(struct device *dev) @@ -753,9 +763,7 @@ static struct via686a_data *via686a_update_device(struct device *dev) (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) & 0xc0) >> 6; - i = via686a_read_value(data, VIA686A_REG_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; + via686a_update_fan_div(data); data->alarms = via686a_read_value(data, VIA686A_REG_ALARM1) | diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index c84b9b4e6960..eed43a008be1 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -33,6 +33,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -1798,8 +1800,7 @@ w83781d_isa_found(unsigned short address) * individually for the probing phase. */ for (port = address; port < address + W83781D_EXTENT; port++) { if (!request_region(port, 1, "w83781d")) { - pr_debug("w83781d: Failed to request port 0x%x\n", - port); + pr_debug("Failed to request port 0x%x\n", port); goto release; } } @@ -1811,7 +1812,7 @@ w83781d_isa_found(unsigned short address) if (inb_p(address + 2) != val || inb_p(address + 3) != val || inb_p(address + 7) != val) { - pr_debug("w83781d: Detection failed at step 1\n"); + pr_debug("Detection failed at step %d\n", 1); goto release; } #undef REALLY_SLOW_IO @@ -1820,14 +1821,14 @@ w83781d_isa_found(unsigned short address) MSB (busy flag) should be clear initially, set after the write. */ save = inb_p(address + W83781D_ADDR_REG_OFFSET); if (save & 0x80) { - pr_debug("w83781d: Detection failed at step 2\n"); + pr_debug("Detection failed at step %d\n", 2); goto release; } val = ~save & 0x7f; outb_p(val, address + W83781D_ADDR_REG_OFFSET); if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) { outb_p(save, address + W83781D_ADDR_REG_OFFSET); - pr_debug("w83781d: Detection failed at step 3\n"); + pr_debug("Detection failed at step %d\n", 3); goto release; } @@ -1835,7 +1836,7 @@ w83781d_isa_found(unsigned short address) outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET); val = inb_p(address + W83781D_DATA_REG_OFFSET); if (val & 0x80) { - pr_debug("w83781d: Detection failed at step 4\n"); + pr_debug("Detection failed at step %d\n", 4); goto release; } outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET); @@ -1844,19 +1845,19 @@ w83781d_isa_found(unsigned short address) val = inb_p(address + W83781D_DATA_REG_OFFSET); if ((!(save & 0x80) && (val != 0xa3)) || ((save & 0x80) && (val != 0x5c))) { - pr_debug("w83781d: Detection failed at step 5\n"); + pr_debug("Detection failed at step %d\n", 5); goto release; } outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET); val = inb_p(address + W83781D_DATA_REG_OFFSET); if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */ - pr_debug("w83781d: Detection failed at step 6\n"); + pr_debug("Detection failed at step %d\n", 6); goto release; } /* The busy flag should be clear again */ if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) { - pr_debug("w83781d: Detection failed at step 7\n"); + pr_debug("Detection failed at step %d\n", 7); goto release; } @@ -1871,7 +1872,7 @@ w83781d_isa_found(unsigned short address) found = 1; if (found) - pr_info("w83781d: Found a %s chip at %#x\n", + pr_info("Found a %s chip at %#x\n", val == 0x30 ? "W83782D" : "W83781D", (int)address); release: @@ -1894,21 +1895,19 @@ w83781d_isa_device_add(unsigned short address) pdev = platform_device_alloc("w83781d", address); if (!pdev) { err = -ENOMEM; - printk(KERN_ERR "w83781d: Device allocation failed\n"); + pr_err("Device allocation failed\n"); goto exit; } err = platform_device_add_resources(pdev, &res, 1); if (err) { - printk(KERN_ERR "w83781d: Device resource addition failed " - "(%d)\n", err); + pr_err("Device resource addition failed (%d)\n", err); goto exit_device_put; } err = platform_device_add(pdev); if (err) { - printk(KERN_ERR "w83781d: Device addition failed (%d)\n", - err); + pr_err("Device addition failed (%d)\n", err); goto exit_device_put; } diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 679718e6b017..63841f8cec07 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -691,7 +691,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, } static ssize_t -show_regs_chassis(struct device *dev, struct device_attribute *attr, +show_chassis(struct device *dev, struct device_attribute *attr, char *buf) { struct w83792d_data *data = w83792d_update_device(dev); @@ -699,6 +699,16 @@ show_regs_chassis(struct device *dev, struct device_attribute *attr, } static ssize_t +show_regs_chassis(struct device *dev, struct device_attribute *attr, + char *buf) +{ + dev_warn(dev, + "Attribute %s is deprecated, use intrusion0_alarm instead\n", + "chassis"); + return show_chassis(dev, attr, buf); +} + +static ssize_t show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf) { struct w83792d_data *data = w83792d_update_device(dev); @@ -706,7 +716,7 @@ show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -store_chassis_clear(struct device *dev, struct device_attribute *attr, +store_chassis_clear_legacy(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); @@ -714,6 +724,10 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr, u32 val; u8 temp1 = 0, temp2 = 0; + dev_warn(dev, + "Attribute %s is deprecated, use intrusion0_alarm instead\n", + "chassis_clear"); + val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->chassis_clear = SENSORS_LIMIT(val, 0 ,1); @@ -726,6 +740,27 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t +store_chassis_clear(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83792d_data *data = i2c_get_clientdata(client); + unsigned long val; + u8 reg; + + if (strict_strtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + reg = w83792d_read_value(client, W83792D_REG_CHASSIS_CLR); + w83792d_write_value(client, W83792D_REG_CHASSIS_CLR, reg | 0x80); + data->valid = 0; /* Force cache refresh */ + mutex_unlock(&data->update_lock); + + return count; +} + /* For Smart Fan I / Thermal Cruise */ static ssize_t show_thermal_cruise(struct device *dev, struct device_attribute *attr, @@ -1012,7 +1047,9 @@ static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22); static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23); static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, - show_chassis_clear, store_chassis_clear); + show_chassis_clear, store_chassis_clear_legacy); +static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, + show_chassis, store_chassis_clear); static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0); static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2); @@ -1214,6 +1251,7 @@ static struct attribute *w83792d_attributes[] = { &dev_attr_alarms.attr, &dev_attr_chassis.attr, &dev_attr_chassis_clear.attr, + &dev_attr_intrusion0_alarm.attr, &sensor_dev_attr_tolerance1.dev_attr.attr, &sensor_dev_attr_thermal_cruise1.dev_attr.attr, &sensor_dev_attr_tolerance2.dev_attr.attr, diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 8e540ada47d2..e3bdedfb5347 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -51,7 +51,6 @@ #define WATCHDOG_TIMEOUT 2 /* 2 minute default timeout */ /* Addresses to scan */ -static DEFINE_MUTEX(watchdog_mutex); static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; @@ -421,14 +420,17 @@ store_beep_enable(struct device *dev, struct device_attribute *attr, /* Write any value to clear chassis alarm */ static ssize_t -store_chassis_clear(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +store_chassis_clear_legacy(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); u8 val; + dev_warn(dev, "Attribute chassis is deprecated, " + "use intrusion0_alarm instead\n"); + mutex_lock(&data->update_lock); val = w83793_read_value(client, W83793_REG_CLR_CHASSIS); val |= 0x80; @@ -437,6 +439,28 @@ store_chassis_clear(struct device *dev, return count; } +/* Write 0 to clear chassis alarm */ +static ssize_t +store_chassis_clear(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83793_data *data = i2c_get_clientdata(client); + unsigned long val; + u8 reg; + + if (strict_strtoul(buf, 10, &val) || val != 0) + return -EINVAL; + + mutex_lock(&data->update_lock); + reg = w83793_read_value(client, W83793_REG_CLR_CHASSIS); + w83793_write_value(client, W83793_REG_CLR_CHASSIS, reg | 0x80); + data->valid = 0; /* Force cache refresh */ + mutex_unlock(&data->update_lock); + return count; +} + #define FAN_INPUT 0 #define FAN_MIN 1 static ssize_t @@ -1102,6 +1126,8 @@ static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm); static struct sensor_device_attribute_2 sda_single_files[] = { SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep, + store_chassis_clear_legacy, ALARM_STATUS, 30), + SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, store_chassis_clear, ALARM_STATUS, 30), SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable, store_beep_enable, NOT_USED, NOT_USED), @@ -1323,7 +1349,7 @@ static ssize_t watchdog_write(struct file *filp, const char __user *buf, static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - static struct watchdog_info ident = { + struct watchdog_info ident = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_CARDRESET, @@ -1333,7 +1359,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, int val, ret = 0; struct w83793_data *data = filp->private_data; - mutex_lock(&watchdog_mutex); switch (cmd) { case WDIOC_GETSUPPORT: if (!nowayout) @@ -1387,7 +1412,6 @@ static long watchdog_ioctl(struct file *filp, unsigned int cmd, default: ret = -ENOTTY; } - mutex_unlock(&watchdog_mutex); return ret; } diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index cdbc7448491e..845232d7f611 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -458,6 +458,7 @@ static void w83795_update_limits(struct i2c_client *client) { struct w83795_data *data = i2c_get_clientdata(client); int i, limit; + u8 lsb; /* Read the voltage limits */ for (i = 0; i < ARRAY_SIZE(data->in); i++) { @@ -479,9 +480,8 @@ static void w83795_update_limits(struct i2c_client *client) } /* Read the fan limits */ + lsb = 0; /* Silent false gcc warning */ for (i = 0; i < ARRAY_SIZE(data->fan); i++) { - u8 lsb; - /* Each register contains LSB for 2 fans, but we want to * read it only once to save time */ if ((i & 1) == 0 && (data->has_fan & (3 << i))) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index c9fffd0389fe..2bd3469b3071 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -434,7 +434,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controler has timedout, re-init the h/w */ + /* controller has timedout, re-init the h/w */ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); (void) init_hw(dev); status = -ETIMEDOUT; @@ -498,7 +498,7 @@ static int write_i2c(struct nmk_i2c_dev *dev) } if (timeout == 0) { - /* controler has timedout, re-init the h/w */ + /* controller has timedout, re-init the h/w */ dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n"); (void) init_hw(dev); status = -ETIMEDOUT; diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 4bb997aa39d0..83d2e19d31ae 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -689,7 +689,7 @@ struct t3_swrq { * A T3 WQ implements both the SQ and RQ. */ struct t3_wq { - union t3_wr *queue; /* DMA accessable memory */ + union t3_wr *queue; /* DMA accessible memory */ dma_addr_t dma_addr; /* DMA address for HW */ DEFINE_DMA_UNMAP_ADDR(mapping); /* unmap kruft */ u32 error; /* 1 once we go to ERROR */ diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index cc600c2dd0b3..2fe19ec9ba60 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -46,7 +46,6 @@ #include <linux/timer.h> #include <linux/io.h> #include <linux/kfifo.h> -#include <linux/mutex.h> #include <asm/byteorder.h> diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index dbbb0e85afe4..abd409d592ef 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -332,7 +332,7 @@ MODULE_PARM_DESC(txselect, \ #define krp_serdesctrl KREG_IBPORT_IDX(IBSerdesCtrl) /* - * Per-context kernel registers. Acess only with qib_read_kreg_ctxt() + * Per-context kernel registers. Access only with qib_read_kreg_ctxt() * or qib_write_kreg_ctxt() */ #define krc_rcvhdraddr KREG_IDX(RcvHdrAddr0) diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 5b596165b571..56eb471b5576 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -255,6 +255,16 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. +config JOYSTICK_AS5011 + tristate "Austria Microsystem AS5011 joystick" + depends on I2C + help + Say Y here if you have an AS5011 digital joystick connected to your + system. + + To compile this driver as a module, choose M here: the + module will be called as5011. + config JOYSTICK_JOYDUMP tristate "Gameport data dumper" select GAMEPORT diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile index f3a8cbe2abb6..92dc0de9dfed 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o +obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o obj-$(CONFIG_JOYSTICK_DB9) += db9.o diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c new file mode 100644 index 000000000000..f6732b57ca07 --- /dev/null +++ b/drivers/input/joystick/as5011.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com> + * Sponsored by ARMadeus Systems + * + * 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 + * + * Driver for Austria Microsystems joysticks AS5011 + * + * TODO: + * - Power on the chip when open() and power down when close() + * - Manage power mode + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/input/as5011.h> +#include <linux/slab.h> + +#define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick" +#define MODULE_DEVICE_ALIAS "as5011" + +MODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* registers */ +#define AS5011_CTRL1 0x76 +#define AS5011_CTRL2 0x75 +#define AS5011_XP 0x43 +#define AS5011_XN 0x44 +#define AS5011_YP 0x53 +#define AS5011_YN 0x54 +#define AS5011_X_REG 0x41 +#define AS5011_Y_REG 0x42 +#define AS5011_X_RES_INT 0x51 +#define AS5011_Y_RES_INT 0x52 + +/* CTRL1 bits */ +#define AS5011_CTRL1_LP_PULSED 0x80 +#define AS5011_CTRL1_LP_ACTIVE 0x40 +#define AS5011_CTRL1_LP_CONTINUE 0x20 +#define AS5011_CTRL1_INT_WUP_EN 0x10 +#define AS5011_CTRL1_INT_ACT_EN 0x08 +#define AS5011_CTRL1_EXT_CLK_EN 0x04 +#define AS5011_CTRL1_SOFT_RST 0x02 +#define AS5011_CTRL1_DATA_VALID 0x01 + +/* CTRL2 bits */ +#define AS5011_CTRL2_EXT_SAMPLE_EN 0x08 +#define AS5011_CTRL2_RC_BIAS_ON 0x04 +#define AS5011_CTRL2_INV_SPINNING 0x02 + +#define AS5011_MAX_AXIS 80 +#define AS5011_MIN_AXIS (-80) +#define AS5011_FUZZ 8 +#define AS5011_FLAT 40 + +struct as5011_device { + struct input_dev *input_dev; + struct i2c_client *i2c_client; + unsigned int button_gpio; + unsigned int button_irq; + unsigned int axis_irq; +}; + +static int as5011_i2c_write(struct i2c_client *client, + uint8_t aregaddr, + uint8_t avalue) +{ + uint8_t data[2] = { aregaddr, avalue }; + struct i2c_msg msg = { + client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data + }; + int error; + + error = i2c_transfer(client->adapter, &msg, 1); + return error < 0 ? error : 0; +} + +static int as5011_i2c_read(struct i2c_client *client, + uint8_t aregaddr, signed char *value) +{ + uint8_t data[2] = { aregaddr }; + struct i2c_msg msg_set[2] = { + { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data }, + { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data } + }; + int error; + + error = i2c_transfer(client->adapter, msg_set, 2); + if (error < 0) + return error; + + *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0]; + return 0; +} + +static irqreturn_t as5011_button_interrupt(int irq, void *dev_id) +{ + struct as5011_device *as5011 = dev_id; + int val = gpio_get_value_cansleep(as5011->button_gpio); + + input_report_key(as5011->input_dev, BTN_JOYSTICK, !val); + input_sync(as5011->input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id) +{ + struct as5011_device *as5011 = dev_id; + int error; + signed char x, y; + + error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x); + if (error < 0) + goto out; + + error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y); + if (error < 0) + goto out; + + input_report_abs(as5011->input_dev, ABS_X, x); + input_report_abs(as5011->input_dev, ABS_Y, y); + input_sync(as5011->input_dev); + +out: + return IRQ_HANDLED; +} + +static int __devinit as5011_configure_chip(struct as5011_device *as5011, + const struct as5011_platform_data *plat_dat) +{ + struct i2c_client *client = as5011->i2c_client; + int error; + signed char value; + + /* chip soft reset */ + error = as5011_i2c_write(client, AS5011_CTRL1, + AS5011_CTRL1_SOFT_RST); + if (error < 0) { + dev_err(&client->dev, "Soft reset failed\n"); + return error; + } + + mdelay(10); + + error = as5011_i2c_write(client, AS5011_CTRL1, + AS5011_CTRL1_LP_PULSED | + AS5011_CTRL1_LP_ACTIVE | + AS5011_CTRL1_INT_ACT_EN); + if (error < 0) { + dev_err(&client->dev, "Power config failed\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_CTRL2, + AS5011_CTRL2_INV_SPINNING); + if (error < 0) { + dev_err(&client->dev, "Can't invert spinning\n"); + return error; + } + + /* write threshold */ + error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn); + if (error < 0) { + dev_err(&client->dev, "Can't write threshold\n"); + return error; + } + + /* to free irq gpio in chip */ + error = as5011_i2c_read(client, AS5011_X_RES_INT, &value); + if (error < 0) { + dev_err(&client->dev, "Can't read i2c X resolution value\n"); + return error; + } + + return 0; +} + +static int __devinit as5011_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct as5011_platform_data *plat_data; + struct as5011_device *as5011; + struct input_dev *input_dev; + int irq; + int error; + + plat_data = client->dev.platform_data; + if (!plat_data) + return -EINVAL; + + if (!plat_data->axis_irq) { + dev_err(&client->dev, "No axis IRQ?\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_PROTOCOL_MANGLING)) { + dev_err(&client->dev, + "need i2c bus that supports protocol mangling\n"); + return -ENODEV; + } + + as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!as5011 || !input_dev) { + dev_err(&client->dev, + "Can't allocate memory for device structure\n"); + error = -ENOMEM; + goto err_free_mem; + } + + as5011->i2c_client = client; + as5011->input_dev = input_dev; + as5011->button_gpio = plat_data->button_gpio; + as5011->axis_irq = plat_data->axis_irq; + + input_dev->name = "Austria Microsystem as5011 joystick"; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(BTN_JOYSTICK, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_X, + AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); + input_set_abs_params(as5011->input_dev, ABS_Y, + AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT); + + error = gpio_request(as5011->button_gpio, "AS5011 button"); + if (error < 0) { + dev_err(&client->dev, "Failed to request button gpio\n"); + goto err_free_mem; + } + + irq = gpio_to_irq(as5011->button_gpio); + if (irq < 0) { + dev_err(&client->dev, + "Failed to get irq number for button gpio\n"); + goto err_free_button_gpio; + } + + as5011->button_irq = irq; + + error = request_threaded_irq(as5011->button_irq, + NULL, as5011_button_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "as5011_button", as5011); + if (error < 0) { + dev_err(&client->dev, + "Can't allocate button irq %d\n", as5011->button_irq); + goto err_free_button_gpio; + } + + error = as5011_configure_chip(as5011, plat_data); + if (error) + goto err_free_button_irq; + + error = request_threaded_irq(as5011->axis_irq, NULL, + as5011_axis_interrupt, + plat_data->axis_irqflags, + "as5011_joystick", as5011); + if (error) { + dev_err(&client->dev, + "Can't allocate axis irq %d\n", plat_data->axis_irq); + goto err_free_button_irq; + } + + error = input_register_device(as5011->input_dev); + if (error) { + dev_err(&client->dev, "Failed to register input device\n"); + goto err_free_axis_irq; + } + + i2c_set_clientdata(client, as5011); + + return 0; + +err_free_axis_irq: + free_irq(as5011->axis_irq, as5011); +err_free_button_irq: + free_irq(as5011->button_irq, as5011); +err_free_button_gpio: + gpio_free(as5011->button_gpio); +err_free_mem: + input_free_device(input_dev); + kfree(as5011); + + return error; +} + +static int __devexit as5011_remove(struct i2c_client *client) +{ + struct as5011_device *as5011 = i2c_get_clientdata(client); + + free_irq(as5011->axis_irq, as5011); + free_irq(as5011->button_irq, as5011); + gpio_free(as5011->button_gpio); + + input_unregister_device(as5011->input_dev); + kfree(as5011); + + return 0; +} + +static const struct i2c_device_id as5011_id[] = { + { MODULE_DEVICE_ALIAS, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as5011_id); + +static struct i2c_driver as5011_driver = { + .driver = { + .name = "as5011", + }, + .probe = as5011_probe, + .remove = __devexit_p(as5011_remove), + .id_table = as5011_id, +}; + +static int __init as5011_init(void) +{ + return i2c_add_driver(&as5011_driver); +} +module_init(as5011_init); + +static void __exit as5011_exit(void) +{ + i2c_del_driver(&as5011_driver); +} +module_exit(as5011_exit); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index f829998fabe6..7b3c0b8fa432 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -12,18 +12,6 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD -config KEYBOARD_AAED2000 - tristate "AAED-2000 keyboard" - depends on MACH_AAED2000 - select INPUT_POLLDEV - default y - help - Say Y here to enable the keyboard on the Agilent AAED-2000 - development board. - - To compile this driver as a module, choose M here: the - module will be called aaed2000_kbd. - config KEYBOARD_ADP5520 tristate "Keypad Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 8933e9ca938d..4e5571b72cda 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -4,7 +4,6 @@ # Each configuration option enables a list of files. -obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c deleted file mode 100644 index 18222a689a03..000000000000 --- a/drivers/input/keyboard/aaed2000_kbd.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Keyboard driver for the AAED-2000 dev board - * - * Copyright (c) 2006 Nicolas Bellido Y Ortega - * - * Based on corgikbd.c - * - * 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/delay.h> -#include <linux/platform_device.h> -#include <linux/init.h> -#include <linux/input-polldev.h> -#include <linux/interrupt.h> -#include <linux/jiffies.h> -#include <linux/module.h> -#include <linux/slab.h> - -#include <mach/hardware.h> -#include <mach/aaed2000.h> - -#define KB_ROWS 12 -#define KB_COLS 8 -#define KB_ROWMASK(r) (1 << (r)) -#define SCANCODE(r,c) (((c) * KB_ROWS) + (r)) -#define NR_SCANCODES (KB_COLS * KB_ROWS) - -#define SCAN_INTERVAL (50) /* ms */ -#define KB_ACTIVATE_DELAY (20) /* us */ - -static unsigned char aaedkbd_keycode[NR_SCANCODES] = { - KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, 0, KEY_SPACE, KEY_KP6, 0, KEY_KPDOT, 0, 0, - KEY_K, KEY_M, KEY_O, KEY_DOT, KEY_SLASH, 0, KEY_F, 0, 0, 0, KEY_LEFTSHIFT, 0, - KEY_I, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 0, 0, 0, 0, KEY_RIGHTSHIFT, 0, - KEY_8, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, 0, 0, 0, 0, 0, 0, 0, - KEY_J, KEY_H, KEY_B, KEY_KP8, KEY_KP4, 0, KEY_C, KEY_D, KEY_S, KEY_A, 0, KEY_CAPSLOCK, - KEY_Y, KEY_U, KEY_N, KEY_T, 0, 0, KEY_R, KEY_E, KEY_W, KEY_Q, 0, KEY_TAB, - KEY_7, KEY_6, KEY_G, 0, KEY_5, 0, KEY_4, KEY_3, KEY_2, KEY_1, 0, KEY_GRAVE, - 0, 0, KEY_COMMA, 0, KEY_KP2, 0, KEY_V, KEY_LEFTALT, KEY_X, KEY_Z, 0, KEY_LEFTCTRL -}; - -struct aaedkbd { - unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)]; - struct input_polled_dev *poll_dev; - int kbdscan_state[KB_COLS]; - int kbdscan_count[KB_COLS]; -}; - -#define KBDSCAN_STABLE_COUNT 2 - -static void aaedkbd_report_col(struct aaedkbd *aaedkbd, - unsigned int col, unsigned int rowd) -{ - unsigned int scancode, pressed; - unsigned int row; - - for (row = 0; row < KB_ROWS; row++) { - scancode = SCANCODE(row, col); - pressed = rowd & KB_ROWMASK(row); - - input_report_key(aaedkbd->poll_dev->input, - aaedkbd->keycode[scancode], pressed); - } -} - -/* Scan the hardware keyboard and push any changes up through the input layer */ -static void aaedkbd_poll(struct input_polled_dev *dev) -{ - struct aaedkbd *aaedkbd = dev->private; - unsigned int col, rowd; - - col = 0; - do { - AAEC_GPIO_KSCAN = col + 8; - udelay(KB_ACTIVATE_DELAY); - rowd = AAED_EXT_GPIO & AAED_EGPIO_KBD_SCAN; - - if (rowd != aaedkbd->kbdscan_state[col]) { - aaedkbd->kbdscan_count[col] = 0; - aaedkbd->kbdscan_state[col] = rowd; - } else if (++aaedkbd->kbdscan_count[col] >= KBDSCAN_STABLE_COUNT) { - aaedkbd_report_col(aaedkbd, col, rowd); - col++; - } - } while (col < KB_COLS); - - AAEC_GPIO_KSCAN = 0x07; - input_sync(dev->input); -} - -static int __devinit aaedkbd_probe(struct platform_device *pdev) -{ - struct aaedkbd *aaedkbd; - struct input_polled_dev *poll_dev; - struct input_dev *input_dev; - int i; - int error; - - aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL); - poll_dev = input_allocate_polled_device(); - if (!aaedkbd || !poll_dev) { - error = -ENOMEM; - goto fail; - } - - platform_set_drvdata(pdev, aaedkbd); - - aaedkbd->poll_dev = poll_dev; - memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode)); - - poll_dev->private = aaedkbd; - poll_dev->poll = aaedkbd_poll; - poll_dev->poll_interval = SCAN_INTERVAL; - - input_dev = poll_dev->input; - input_dev->name = "AAED-2000 Keyboard"; - input_dev->phys = "aaedkbd/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0x0001; - input_dev->id.product = 0x0001; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &pdev->dev; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - input_dev->keycode = aaedkbd->keycode; - input_dev->keycodesize = sizeof(unsigned char); - input_dev->keycodemax = ARRAY_SIZE(aaedkbd_keycode); - - for (i = 0; i < ARRAY_SIZE(aaedkbd_keycode); i++) - set_bit(aaedkbd->keycode[i], input_dev->keybit); - clear_bit(0, input_dev->keybit); - - error = input_register_polled_device(aaedkbd->poll_dev); - if (error) - goto fail; - - return 0; - - fail: kfree(aaedkbd); - input_free_polled_device(poll_dev); - return error; -} - -static int __devexit aaedkbd_remove(struct platform_device *pdev) -{ - struct aaedkbd *aaedkbd = platform_get_drvdata(pdev); - - input_unregister_polled_device(aaedkbd->poll_dev); - input_free_polled_device(aaedkbd->poll_dev); - kfree(aaedkbd); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:aaed2000-keyboard"); - -static struct platform_driver aaedkbd_driver = { - .probe = aaedkbd_probe, - .remove = __devexit_p(aaedkbd_remove), - .driver = { - .name = "aaed2000-keyboard", - .owner = THIS_MODULE, - }, -}; - -static int __init aaedkbd_init(void) -{ - return platform_driver_register(&aaedkbd_driver); -} - -static void __exit aaedkbd_exit(void) -{ - platform_driver_unregister(&aaedkbd_driver); -} - -module_init(aaedkbd_init); -module_exit(aaedkbd_exit); - -MODULE_AUTHOR("Nicolas Bellido Y Ortega"); -MODULE_DESCRIPTION("AAED-2000 Keyboard Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index bcb1fdedb595..307eef77a172 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -229,7 +229,7 @@ config SERIO_PS2MULT tristate "TQC PS/2 multiplexer" help Say Y here if you have the PS/2 line multiplexer like the one - present on TQC boads. + present on TQC boards. To compile this driver as a module, choose M here: the module will be called ps2mult. diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5ae0fc4578fe..bb9f5d31f0d0 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -424,6 +424,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), }, }, + { + /* Dell Vostro V13 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), + }, + }, { } }; @@ -545,6 +552,17 @@ static const struct dmi_system_id __initconst i8042_dmi_laptop_table[] = { }; #endif +static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { + { + /* Dell Vostro V13 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), + }, + }, + { } +}; + /* * Some Wistron based laptops need us to explicitly enable the 'Dritek * keyboard extension' to make their extra keys start generating scancodes. @@ -896,6 +914,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = true; + if (dmi_check_system(i8042_dmi_notimeout_table)) + i8042_notimeout = true; + if (dmi_check_system(i8042_dmi_dritek_table)) i8042_dritek = true; #endif /* CONFIG_X86 */ diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c04ff00a3663..ac4c93689ab9 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -63,6 +63,10 @@ static bool i8042_noloop; module_param_named(noloop, i8042_noloop, bool, 0); MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); +static bool i8042_notimeout; +module_param_named(notimeout, i8042_notimeout, bool, 0); +MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042"); + #ifdef CONFIG_X86 static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); @@ -504,7 +508,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) } else { dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); + ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0); port_no = (str & I8042_STR_AUXDATA) ? I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 07ac77d393a4..0c9f4b158ff0 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -610,7 +610,7 @@ config TOUCHSCREEN_USB_ZYTRONIC config TOUCHSCREEN_USB_ETT_TC45USB default y - bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED + bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EMBEDDED depends on TOUCHSCREEN_USB_COMPOSITE config TOUCHSCREEN_USB_NEXIO diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index d82a38ee9a3e..4e4e58cec6c8 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -10,14 +10,16 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/types.h> +#include <linux/pm.h> #include "ad7879.h" #define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */ #ifdef CONFIG_PM -static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message) +static int ad7879_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct ad7879 *ts = i2c_get_clientdata(client); ad7879_suspend(ts); @@ -25,17 +27,17 @@ static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message) return 0; } -static int ad7879_i2c_resume(struct i2c_client *client) +static int ad7879_i2c_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct ad7879 *ts = i2c_get_clientdata(client); ad7879_resume(ts); return 0; } -#else -# define ad7879_i2c_suspend NULL -# define ad7879_i2c_resume NULL + +static SIMPLE_DEV_PM_OPS(ad7879_i2c_pm, ad7879_i2c_suspend, ad7879_i2c_resume); #endif /* All registers are word-sized. @@ -117,11 +119,12 @@ static struct i2c_driver ad7879_i2c_driver = { .driver = { .name = "ad7879", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &ad7879_i2c_pm, +#endif }, .probe = ad7879_i2c_probe, .remove = __devexit_p(ad7879_i2c_remove), - .suspend = ad7879_i2c_suspend, - .resume = ad7879_i2c_resume, .id_table = ad7879_id, }; diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index d0c3a7229adf..a93c5c26ab3f 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -280,8 +280,9 @@ err_free_mem: } #ifdef CONFIG_PM -static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg) +static int cy8ctmg110_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct cy8ctmg110 *ts = i2c_get_clientdata(client); if (device_may_wakeup(&client->dev)) @@ -293,8 +294,9 @@ static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int cy8ctmg110_resume(struct i2c_client *client) +static int cy8ctmg110_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct cy8ctmg110 *ts = i2c_get_clientdata(client); if (device_may_wakeup(&client->dev)) @@ -305,6 +307,8 @@ static int cy8ctmg110_resume(struct i2c_client *client) } return 0; } + +static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume); #endif static int __devexit cy8ctmg110_remove(struct i2c_client *client) @@ -335,14 +339,13 @@ static struct i2c_driver cy8ctmg110_driver = { .driver = { .owner = THIS_MODULE, .name = CY8CTMG110_DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &cy8ctmg110_pm, +#endif }, .id_table = cy8ctmg110_idtable, .probe = cy8ctmg110_probe, .remove = __devexit_p(cy8ctmg110_remove), -#ifdef CONFIG_PM - .suspend = cy8ctmg110_suspend, - .resume = cy8ctmg110_resume, -#endif }; static int __init cy8ctmg110_init(void) diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 7a3a916f84a8..7f8f538a9806 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -261,8 +261,9 @@ static int __devexit eeti_ts_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) +static int eeti_ts_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct eeti_ts_priv *priv = i2c_get_clientdata(client); struct input_dev *input_dev = priv->input; @@ -279,8 +280,9 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int eeti_ts_resume(struct i2c_client *client) +static int eeti_ts_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct eeti_ts_priv *priv = i2c_get_clientdata(client); struct input_dev *input_dev = priv->input; @@ -296,9 +298,8 @@ static int eeti_ts_resume(struct i2c_client *client) return 0; } -#else -#define eeti_ts_suspend NULL -#define eeti_ts_resume NULL + +static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume); #endif static const struct i2c_device_id eeti_ts_id[] = { @@ -310,11 +311,12 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id); static struct i2c_driver eeti_ts_driver = { .driver = { .name = "eeti_ts", +#ifdef CONFIG_PM + .pm = &eeti_ts_pm, +#endif }, .probe = eeti_ts_probe, .remove = __devexit_p(eeti_ts_remove), - .suspend = eeti_ts_suspend, - .resume = eeti_ts_resume, .id_table = eeti_ts_id, }; diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index 6ee9940aaf5b..2d84c80ceb66 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -261,25 +261,27 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int mcs5000_ts_suspend(struct i2c_client *client, pm_message_t mesg) +static int mcs5000_ts_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + /* Touch sleep mode */ i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP); return 0; } -static int mcs5000_ts_resume(struct i2c_client *client) +static int mcs5000_ts_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct mcs5000_ts_data *data = i2c_get_clientdata(client); mcs5000_ts_phys_init(data); return 0; } -#else -#define mcs5000_ts_suspend NULL -#define mcs5000_ts_resume NULL + +static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume); #endif static const struct i2c_device_id mcs5000_ts_id[] = { @@ -291,10 +293,11 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id); static struct i2c_driver mcs5000_ts_driver = { .probe = mcs5000_ts_probe, .remove = __devexit_p(mcs5000_ts_remove), - .suspend = mcs5000_ts_suspend, - .resume = mcs5000_ts_resume, .driver = { .name = "mcs5000_ts", +#ifdef CONFIG_PM + .pm = &mcs5000_ts_pm, +#endif }, .id_table = mcs5000_ts_id, }; diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index defe5dd3627c..5803bd0c1cca 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/input.h> #include <linux/interrupt.h> +#include <linux/pm.h> #include <linux/slab.h> #include <asm/io.h> #include <linux/i2c.h> @@ -226,8 +227,9 @@ static int migor_ts_remove(struct i2c_client *client) return 0; } -static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg) +static int migor_ts_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); if (device_may_wakeup(&client->dev)) @@ -236,8 +238,9 @@ static int migor_ts_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int migor_ts_resume(struct i2c_client *client) +static int migor_ts_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct migor_ts_priv *priv = dev_get_drvdata(&client->dev); if (device_may_wakeup(&client->dev)) @@ -246,6 +249,8 @@ static int migor_ts_resume(struct i2c_client *client) return 0; } +static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume); + static const struct i2c_device_id migor_ts_id[] = { { "migor_ts", 0 }, { } @@ -255,11 +260,10 @@ MODULE_DEVICE_TABLE(i2c, migor_ts); static struct i2c_driver migor_ts_driver = { .driver = { .name = "migor_ts", + .pm = &migor_ts_pm, }, .probe = migor_ts_probe, .remove = migor_ts_remove, - .suspend = migor_ts_suspend, - .resume = migor_ts_resume, .id_table = migor_ts_id, }; diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 8ed53aded2d3..5cb8449c909d 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -3,6 +3,7 @@ * * Copyright (c) 2008 Jaya Kumar * Copyright (c) 2010 Red Hat, Inc. + * Copyright (c) 2010 - 2011 Ping Cheng, Wacom. <pingc@wacom.com> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -64,11 +65,11 @@ struct w8001_coord { /* touch query reply packet */ struct w8001_touch_query { + u16 x; + u16 y; u8 panel_res; u8 capacity_res; u8 sensor_id; - u16 x; - u16 y; }; /* @@ -87,9 +88,14 @@ struct w8001 { char phys[32]; int type; unsigned int pktlen; + u16 max_touch_x; + u16 max_touch_y; + u16 max_pen_x; + u16 max_pen_y; + char name[64]; }; -static void parse_data(u8 *data, struct w8001_coord *coord) +static void parse_pen_data(u8 *data, struct w8001_coord *coord) { memset(coord, 0, sizeof(*coord)); @@ -113,11 +119,30 @@ static void parse_data(u8 *data, struct w8001_coord *coord) coord->tilt_y = data[8] & 0x7F; } -static void parse_touch(struct w8001 *w8001) +static void parse_single_touch(u8 *data, struct w8001_coord *coord) +{ + coord->x = (data[1] << 7) | data[2]; + coord->y = (data[3] << 7) | data[4]; + coord->tsw = data[0] & 0x01; +} + +static void scale_touch_coordinates(struct w8001 *w8001, + unsigned int *x, unsigned int *y) +{ + if (w8001->max_pen_x && w8001->max_touch_x) + *x = *x * w8001->max_pen_x / w8001->max_touch_x; + + if (w8001->max_pen_y && w8001->max_touch_y) + *y = *y * w8001->max_pen_y / w8001->max_touch_y; +} + +static void parse_multi_touch(struct w8001 *w8001) { struct input_dev *dev = w8001->dev; unsigned char *data = w8001->data; + unsigned int x, y; int i; + int count = 0; for (i = 0; i < 2; i++) { bool touch = data[0] & (1 << i); @@ -125,15 +150,29 @@ static void parse_touch(struct w8001 *w8001) input_mt_slot(dev, i); input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch); if (touch) { - int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]); - int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]); + x = (data[6 * i + 1] << 7) | data[6 * i + 2]; + y = (data[6 * i + 3] << 7) | data[6 * i + 4]; /* data[5,6] and [11,12] is finger capacity */ + /* scale to pen maximum */ + scale_touch_coordinates(w8001, &x, &y); + input_report_abs(dev, ABS_MT_POSITION_X, x); input_report_abs(dev, ABS_MT_POSITION_Y, y); + count++; } } + /* emulate single touch events when stylus is out of proximity. + * This is to make single touch backward support consistent + * across all Wacom single touch devices. + */ + if (w8001->type != BTN_TOOL_PEN && + w8001->type != BTN_TOOL_RUBBER) { + w8001->type = count == 1 ? BTN_TOOL_FINGER : KEY_RESERVED; + input_mt_report_pointer_emulation(dev, true); + } + input_sync(dev); } @@ -152,6 +191,15 @@ static void parse_touchquery(u8 *data, struct w8001_touch_query *query) query->y = data[5] << 9; query->y |= data[6] << 2; query->y |= (data[2] >> 3) & 0x3; + + /* Early days' single-finger touch models need the following defaults */ + if (!query->x && !query->y) { + query->x = 1024; + query->y = 1024; + if (query->panel_res) + query->x = query->y = (1 << query->panel_res); + query->panel_res = 10; + } } static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) @@ -161,16 +209,15 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) /* * We have 1 bit for proximity (rdy) and 3 bits for tip, side, * side2/eraser. If rdy && f2 are set, this can be either pen + side2, - * or eraser. assume + * or eraser. Assume: * - if dev is already in proximity and f2 is toggled → pen + side2 * - if dev comes into proximity with f2 set → eraser * If f2 disappears after assuming eraser, fake proximity out for * eraser and in for pen. */ - if (!w8001->type) { - w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - } else if (w8001->type == BTN_TOOL_RUBBER) { + switch (w8001->type) { + case BTN_TOOL_RUBBER: if (!coord->f2) { input_report_abs(dev, ABS_PRESSURE, 0); input_report_key(dev, BTN_TOUCH, 0); @@ -180,8 +227,21 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) input_sync(dev); w8001->type = BTN_TOOL_PEN; } - } else { + break; + + case BTN_TOOL_FINGER: + input_report_key(dev, BTN_TOUCH, 0); + input_report_key(dev, BTN_TOOL_FINGER, 0); + input_sync(dev); + /* fall through */ + + case KEY_RESERVED: + w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + break; + + default: input_report_key(dev, BTN_STYLUS2, coord->f2); + break; } input_report_abs(dev, ABS_X, coord->x); @@ -193,7 +253,26 @@ static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) input_sync(dev); if (!coord->rdy) - w8001->type = 0; + w8001->type = KEY_RESERVED; +} + +static void report_single_touch(struct w8001 *w8001, struct w8001_coord *coord) +{ + struct input_dev *dev = w8001->dev; + unsigned int x = coord->x; + unsigned int y = coord->y; + + /* scale to pen maximum */ + scale_touch_coordinates(w8001, &x, &y); + + input_report_abs(dev, ABS_X, x); + input_report_abs(dev, ABS_Y, y); + input_report_key(dev, BTN_TOUCH, coord->tsw); + input_report_key(dev, BTN_TOOL_FINGER, coord->tsw); + + input_sync(dev); + + w8001->type = coord->tsw ? BTN_TOOL_FINGER : KEY_RESERVED; } static irqreturn_t w8001_interrupt(struct serio *serio, @@ -214,9 +293,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio, case W8001_PKTLEN_TOUCH93 - 1: case W8001_PKTLEN_TOUCH9A - 1: - /* ignore one-finger touch packet. */ - if (w8001->pktlen == w8001->idx) + tmp = w8001->data[0] & W8001_TOUCH_BYTE; + if (tmp != W8001_TOUCH_BYTE) + break; + + if (w8001->pktlen == w8001->idx) { w8001->idx = 0; + if (w8001->type != BTN_TOOL_PEN && + w8001->type != BTN_TOOL_RUBBER) { + parse_single_touch(w8001->data, &coord); + report_single_touch(w8001, &coord); + } + } break; /* Pen coordinates packet */ @@ -225,18 +313,18 @@ static irqreturn_t w8001_interrupt(struct serio *serio, if (unlikely(tmp == W8001_TAB_BYTE)) break; - tmp = (w8001->data[0] & W8001_TOUCH_BYTE); + tmp = w8001->data[0] & W8001_TOUCH_BYTE; if (tmp == W8001_TOUCH_BYTE) break; w8001->idx = 0; - parse_data(w8001->data, &coord); + parse_pen_data(w8001->data, &coord); report_pen_events(w8001, &coord); break; /* control packet */ case W8001_PKTLEN_TPCCTL - 1: - tmp = (w8001->data[0] & W8001_TOUCH_MASK); + tmp = w8001->data[0] & W8001_TOUCH_MASK; if (tmp == W8001_TOUCH_BYTE) break; @@ -249,7 +337,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio, /* 2 finger touch packet */ case W8001_PKTLEN_TOUCH2FG - 1: w8001->idx = 0; - parse_touch(w8001); + parse_multi_touch(w8001); break; } @@ -279,6 +367,7 @@ static int w8001_setup(struct w8001 *w8001) { struct input_dev *dev = w8001->dev; struct w8001_coord coord; + struct w8001_touch_query touch; int error; error = w8001_command(w8001, W8001_CMD_STOP, false); @@ -287,14 +376,21 @@ static int w8001_setup(struct w8001 *w8001) msleep(250); /* wait 250ms before querying the device */ + dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name)); + /* penabled? */ error = w8001_command(w8001, W8001_CMD_QUERY, true); if (!error) { + __set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOOL_PEN, dev->keybit); __set_bit(BTN_TOOL_RUBBER, dev->keybit); __set_bit(BTN_STYLUS, dev->keybit); __set_bit(BTN_STYLUS2, dev->keybit); - parse_data(w8001->response, &coord); + + parse_pen_data(w8001->response, &coord); + w8001->max_pen_x = coord.x; + w8001->max_pen_y = coord.y; input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); @@ -303,6 +399,8 @@ static int w8001_setup(struct w8001 *w8001) input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); } + w8001->id = 0x90; + strlcat(w8001->name, " Penabled", sizeof(w8001->name)); } /* Touch enabled? */ @@ -313,24 +411,38 @@ static int w8001_setup(struct w8001 *w8001) * second byte is empty, which indicates touch is not supported. */ if (!error && w8001->response[1]) { - struct w8001_touch_query touch; + __set_bit(BTN_TOUCH, dev->keybit); + __set_bit(BTN_TOOL_FINGER, dev->keybit); parse_touchquery(w8001->response, &touch); + w8001->max_touch_x = touch.x; + w8001->max_touch_y = touch.y; + + /* scale to pen maximum */ + if (w8001->max_pen_x && w8001->max_pen_y) { + touch.x = w8001->max_pen_x; + touch.y = w8001->max_pen_y; + } input_set_abs_params(dev, ABS_X, 0, touch.x, 0, 0); input_set_abs_params(dev, ABS_Y, 0, touch.y, 0, 0); - __set_bit(BTN_TOOL_FINGER, dev->keybit); switch (touch.sensor_id) { case 0: case 2: w8001->pktlen = W8001_PKTLEN_TOUCH93; + w8001->id = 0x93; + strlcat(w8001->name, " 1FG", sizeof(w8001->name)); break; + case 1: case 3: case 4: w8001->pktlen = W8001_PKTLEN_TOUCH9A; + strlcat(w8001->name, " 1FG", sizeof(w8001->name)); + w8001->id = 0x9a; break; + case 5: w8001->pktlen = W8001_PKTLEN_TOUCH2FG; @@ -341,10 +453,18 @@ static int w8001_setup(struct w8001 *w8001) 0, touch.y, 0, 0); input_set_abs_params(dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); + + strlcat(w8001->name, " 2FG", sizeof(w8001->name)); + if (w8001->max_pen_x && w8001->max_pen_y) + w8001->id = 0xE3; + else + w8001->id = 0xE2; break; } } + strlcat(w8001->name, " Touchscreen", sizeof(w8001->name)); + return w8001_command(w8001, W8001_CMD_START, false); } @@ -384,22 +504,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) } w8001->serio = serio; - w8001->id = serio->id.id; w8001->dev = input_dev; init_completion(&w8001->cmd_done); snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); - input_dev->name = "Wacom W8001 Penabled Serial TouchScreen"; - input_dev->phys = w8001->phys; - input_dev->id.bustype = BUS_RS232; - input_dev->id.vendor = SERIO_W8001; - input_dev->id.product = w8001->id; - input_dev->id.version = 0x0100; - input_dev->dev.parent = &serio->dev; - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(BTN_TOUCH, input_dev->keybit); - serio_set_drvdata(serio, w8001); err = serio_open(serio, drv); if (err) @@ -409,6 +517,14 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) if (err) goto fail3; + input_dev->name = w8001->name; + input_dev->phys = w8001->phys; + input_dev->id.product = w8001->id; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = 0x056a; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &serio->dev; + err = input_register_device(w8001->dev); if (err) goto fail3; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 178942a2ee61..8a3c5cfc4fea 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2318,7 +2318,7 @@ static int gigaset_probe(struct usb_interface *interface, __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode, GIGASET_MODULENAME); if (!cs) @@ -2576,7 +2576,7 @@ static int __init bas_gigaset_init(void) { int result; - /* allocate memory for our driver state and intialize it */ + /* allocate memory for our driver state and initialize it */ driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &gigops, THIS_MODULE); diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index d151dcbf770d..0ef09d0eb96b 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -513,7 +513,7 @@ gigaset_tty_open(struct tty_struct *tty) return -ENODEV; } - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); if (!cs) goto error; @@ -771,7 +771,7 @@ static int __init ser_gigaset_init(void) return rc; } - /* allocate memory for our driver state and intialize it */ + /* allocate memory for our driver state and initialize it */ driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &ops, THIS_MODULE); diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 4a66338f4e7d..5e3300d8a2a5 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -695,7 +695,7 @@ static int gigaset_probe(struct usb_interface *interface, dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); if (!cs) return -ENODEV; @@ -894,7 +894,7 @@ static int __init usb_gigaset_init(void) { int result; - /* allocate memory for our driver state and intialize it */ + /* allocate memory for our driver state and initialize it */ driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, GIGASET_MODULENAME, GIGASET_DEVNAME, &ops, THIS_MODULE); diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h index 74a6ccf9065c..8121e046b739 100644 --- a/drivers/isdn/hardware/mISDN/ipac.h +++ b/drivers/isdn/hardware/mISDN/ipac.h @@ -29,7 +29,7 @@ struct isac_hw { u32 type; u32 off; /* offset to isac regs */ char *name; - spinlock_t *hwlock; /* lock HW acccess */ + spinlock_t *hwlock; /* lock HW access */ read_reg_func *read_reg; write_reg_func *write_reg; fifo_func *read_fifo; @@ -70,7 +70,7 @@ struct ipac_hw { struct hscx_hw hscx[2]; char *name; void *hw; - spinlock_t *hwlock; /* lock HW acccess */ + spinlock_t *hwlock; /* lock HW access */ struct module *owner; u32 type; read_reg_func *read_reg; diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h index 4a134acd44d0..9962bdf699c7 100644 --- a/drivers/isdn/hardware/mISDN/isar.h +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -44,7 +44,7 @@ struct isar_ch { struct isar_hw { struct isar_ch ch[2]; void *hw; - spinlock_t *hwlock; /* lock HW acccess */ + spinlock_t *hwlock; /* lock HW access */ char *name; struct module *owner; read_reg_func *read_reg; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 76d9e673b4e1..309bacf1fadc 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -112,7 +112,7 @@ * Disable rx-data: * If cmx is realized in hardware, rx data will be disabled if requested by * the upper layer. If dtmf decoding is done by software and enabled, rx data - * will not be diabled but blocked to the upper layer. + * will not be disabled but blocked to the upper layer. * * HFC conference engine: * If it is possible to realize all features using hardware, hardware will be diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 33facd0c45d1..80a3ae3c00b9 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -98,7 +98,6 @@ #define LP5521_EXT_CLK_USED 0x08 struct lp5521_engine { - const struct attribute_group *attributes; int id; u8 mode; u8 prog_page; @@ -225,25 +224,22 @@ static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) curr); } -static void lp5521_init_engine(struct lp5521_chip *chip, - const struct attribute_group *attr_group) +static void lp5521_init_engine(struct lp5521_chip *chip) { int i; for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { chip->engines[i].id = i + 1; chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2); chip->engines[i].prog_page = i; - chip->engines[i].attributes = &attr_group[i]; } } -static int lp5521_configure(struct i2c_client *client, - const struct attribute_group *attr_group) +static int lp5521_configure(struct i2c_client *client) { struct lp5521_chip *chip = i2c_get_clientdata(client); int ret; - lp5521_init_engine(chip, attr_group); + lp5521_init_engine(chip); /* Set all PWMs to direct control mode */ ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); @@ -329,9 +325,6 @@ static int lp5521_detect(struct i2c_client *client) /* Set engine mode and create appropriate sysfs attributes, if required. */ static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) { - struct lp5521_chip *chip = engine_to_lp5521(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; int ret = 0; /* if in that mode already do nothing, except for run */ @@ -343,18 +336,10 @@ static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) } else if (mode == LP5521_CMD_LOAD) { lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); lp5521_set_engine_mode(engine, LP5521_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; } else if (mode == LP5521_CMD_DISABLED) { lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); } - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - engine->mode = mode; return ret; @@ -373,6 +358,8 @@ static int lp5521_do_store_load(struct lp5521_engine *engine, while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { /* separate sscanfs because length is working only for %s */ ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); + if (ret != 2) + goto fail; ret = sscanf(c, "%2x", &cmd); if (ret != 1) goto fail; @@ -387,7 +374,10 @@ static int lp5521_do_store_load(struct lp5521_engine *engine, goto fail; mutex_lock(&chip->lock); - ret = lp5521_load_program(engine, pattern); + if (engine->mode == LP5521_CMD_LOAD) + ret = lp5521_load_program(engine, pattern); + else + ret = -EINVAL; mutex_unlock(&chip->lock); if (ret) { @@ -574,20 +564,8 @@ static struct attribute *lp5521_attributes[] = { &dev_attr_engine2_mode.attr, &dev_attr_engine3_mode.attr, &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5521_engine1_attributes[] = { &dev_attr_engine1_load.attr, - NULL -}; - -static struct attribute *lp5521_engine2_attributes[] = { &dev_attr_engine2_load.attr, - NULL -}; - -static struct attribute *lp5521_engine3_attributes[] = { &dev_attr_engine3_load.attr, NULL }; @@ -596,12 +574,6 @@ static const struct attribute_group lp5521_group = { .attrs = lp5521_attributes, }; -static const struct attribute_group lp5521_engine_group[] = { - {.attrs = lp5521_engine1_attributes }, - {.attrs = lp5521_engine2_attributes }, - {.attrs = lp5521_engine3_attributes }, -}; - static int lp5521_register_sysfs(struct i2c_client *client) { struct device *dev = &client->dev; @@ -616,12 +588,6 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) sysfs_remove_group(&dev->kobj, &lp5521_group); - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { - if (chip->engines[i].mode == LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, - chip->engines[i].attributes); - } - for (i = 0; i < chip->num_leds; i++) sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, &lp5521_led_attribute_group); @@ -651,7 +617,8 @@ static int __init lp5521_init_led(struct lp5521_led *led, return -EINVAL; } - snprintf(name, sizeof(name), "%s:channel%d", client->name, chan); + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: client->name, chan); led->cdev.brightness_set = lp5521_set_brightness; led->cdev.name = name; res = led_classdev_register(dev, &led->cdev); @@ -723,7 +690,7 @@ static int lp5521_probe(struct i2c_client *client, dev_info(&client->dev, "%s programmable led chip found\n", id->name); - ret = lp5521_configure(client, lp5521_engine_group); + ret = lp5521_configure(client); if (ret < 0) { dev_err(&client->dev, "error configuring chip\n"); goto fail2; diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 0cc4ead2fd8b..d0c4068ecddd 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -105,7 +105,6 @@ #define SHIFT_MASK(id) (((id) - 1) * 2) struct lp5523_engine { - const struct attribute_group *attributes; int id; u8 mode; u8 prog_page; @@ -403,14 +402,23 @@ static ssize_t store_engine_leds(struct device *dev, struct i2c_client *client = to_i2c_client(dev); struct lp5523_chip *chip = i2c_get_clientdata(client); u16 mux = 0; + ssize_t ret; if (lp5523_mux_parse(buf, &mux, len)) return -EINVAL; + mutex_lock(&chip->lock); + ret = -EINVAL; + if (chip->engines[nr - 1].mode != LP5523_CMD_LOAD) + goto leave; + if (lp5523_load_mux(&chip->engines[nr - 1], mux)) - return -EINVAL; + goto leave; - return len; + ret = len; +leave: + mutex_unlock(&chip->lock); + return ret; } #define store_leds(nr) \ @@ -556,7 +564,11 @@ static int lp5523_do_store_load(struct lp5523_engine *engine, mutex_lock(&chip->lock); - ret = lp5523_load_program(engine, pattern); + if (engine->mode == LP5523_CMD_LOAD) + ret = lp5523_load_program(engine, pattern); + else + ret = -EINVAL; + mutex_unlock(&chip->lock); if (ret) { @@ -737,37 +749,18 @@ static struct attribute *lp5523_attributes[] = { &dev_attr_engine2_mode.attr, &dev_attr_engine3_mode.attr, &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5523_engine1_attributes[] = { &dev_attr_engine1_load.attr, &dev_attr_engine1_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine2_attributes[] = { &dev_attr_engine2_load.attr, &dev_attr_engine2_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine3_attributes[] = { &dev_attr_engine3_load.attr, &dev_attr_engine3_leds.attr, - NULL }; static const struct attribute_group lp5523_group = { .attrs = lp5523_attributes, }; -static const struct attribute_group lp5523_engine_group[] = { - {.attrs = lp5523_engine1_attributes }, - {.attrs = lp5523_engine2_attributes }, - {.attrs = lp5523_engine3_attributes }, -}; - static int lp5523_register_sysfs(struct i2c_client *client) { struct device *dev = &client->dev; @@ -788,10 +781,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) sysfs_remove_group(&dev->kobj, &lp5523_group); - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) - if (chip->engines[i].mode == LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]); - for (i = 0; i < chip->num_leds; i++) sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, &lp5523_led_attribute_group); @@ -802,10 +791,6 @@ static void lp5523_unregister_sysfs(struct i2c_client *client) /*--------------------------------------------------------------*/ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) { - /* engine to chip */ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; int ret = 0; /* if in that mode already do nothing, except for run */ @@ -817,18 +802,10 @@ static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) } else if (mode == LP5523_CMD_LOAD) { lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; } else if (mode == LP5523_CMD_DISABLED) { lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); } - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - engine->mode = mode; return ret; @@ -845,7 +822,6 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); engine->prog_page = id - 1; engine->mux_page = id + 2; - engine->attributes = &lp5523_engine_group[id - 1]; return 0; } @@ -870,7 +846,8 @@ static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, return -EINVAL; } - snprintf(name, 32, "lp5523:channel%d", chan); + snprintf(name, sizeof(name), "%s:channel%d", + pdata->label ?: "lp5523", chan); led->cdev.name = name; led->cdev.brightness_set = lp5523_set_brightness; diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 43d08756d823..afac338d5025 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -200,6 +200,32 @@ static void pca9532_led_work(struct work_struct *work) pca9532_setled(led); } +static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs) +{ + int i = n_devs; + + if (!data) + return; + + while (--i >= 0) { + switch (data->leds[i].type) { + case PCA9532_TYPE_NONE: + break; + case PCA9532_TYPE_LED: + led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); + break; + case PCA9532_TYPE_N2100_BEEP: + if (data->idev != NULL) { + input_unregister_device(data->idev); + cancel_work_sync(&data->work); + data->idev = NULL; + } + break; + } + } +} + static int pca9532_configure(struct i2c_client *client, struct pca9532_data *data, struct pca9532_platform_data *pdata) { @@ -274,25 +300,7 @@ static int pca9532_configure(struct i2c_client *client, return 0; exit: - if (i > 0) - for (i = i - 1; i >= 0; i--) - switch (data->leds[i].type) { - case PCA9532_TYPE_NONE: - break; - case PCA9532_TYPE_LED: - led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); - break; - case PCA9532_TYPE_N2100_BEEP: - if (data->idev != NULL) { - input_unregister_device(data->idev); - input_free_device(data->idev); - cancel_work_sync(&data->work); - data->idev = NULL; - } - break; - } - + pca9532_destroy_devices(data, i); return err; } @@ -329,25 +337,7 @@ static int pca9532_probe(struct i2c_client *client, static int pca9532_remove(struct i2c_client *client) { struct pca9532_data *data = i2c_get_clientdata(client); - int i; - for (i = 0; i < 16; i++) - switch (data->leds[i].type) { - case PCA9532_TYPE_NONE: - break; - case PCA9532_TYPE_LED: - led_classdev_unregister(&data->leds[i].ldev); - cancel_work_sync(&data->leds[i].work); - break; - case PCA9532_TYPE_N2100_BEEP: - if (data->idev != NULL) { - input_unregister_device(data->idev); - input_free_device(data->idev); - cancel_work_sync(&data->work); - data->idev = NULL; - } - break; - } - + pca9532_destroy_devices(data, 16); kfree(data); return 0; } diff --git a/drivers/leds/ledtrig-backlight.c b/drivers/leds/ledtrig-backlight.c index f948e57bd9b8..2b513a2ad7de 100644 --- a/drivers/leds/ledtrig-backlight.c +++ b/drivers/leds/ledtrig-backlight.c @@ -26,6 +26,7 @@ struct bl_trig_notifier { int brightness; int old_status; struct notifier_block notifier; + unsigned invert; }; static int fb_notifier_callback(struct notifier_block *p, @@ -36,23 +37,64 @@ static int fb_notifier_callback(struct notifier_block *p, struct led_classdev *led = n->led; struct fb_event *fb_event = data; int *blank = fb_event->data; + int new_status = *blank ? BLANK : UNBLANK; switch (event) { case FB_EVENT_BLANK : - if (*blank && n->old_status == UNBLANK) { + if (new_status == n->old_status) + break; + + if ((n->old_status == UNBLANK) ^ n->invert) { n->brightness = led->brightness; led_set_brightness(led, LED_OFF); - n->old_status = BLANK; - } else if (!*blank && n->old_status == BLANK) { + } else { led_set_brightness(led, n->brightness); - n->old_status = UNBLANK; } + + n->old_status = new_status; + break; } return 0; } +static ssize_t bl_trig_invert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led = dev_get_drvdata(dev); + struct bl_trig_notifier *n = led->trigger_data; + + return sprintf(buf, "%u\n", n->invert); +} + +static ssize_t bl_trig_invert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t num) +{ + struct led_classdev *led = dev_get_drvdata(dev); + struct bl_trig_notifier *n = led->trigger_data; + unsigned long invert; + int ret; + + ret = strict_strtoul(buf, 10, &invert); + if (ret < 0) + return ret; + + if (invert > 1) + return -EINVAL; + + n->invert = invert; + + /* After inverting, we need to update the LED. */ + if ((n->old_status == BLANK) ^ n->invert) + led_set_brightness(led, LED_OFF); + else + led_set_brightness(led, n->brightness); + + return num; +} +static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store); + static void bl_trig_activate(struct led_classdev *led) { int ret; @@ -66,6 +108,10 @@ static void bl_trig_activate(struct led_classdev *led) return; } + ret = device_create_file(led->dev, &dev_attr_inverted); + if (ret) + goto err_invert; + n->led = led; n->brightness = led->brightness; n->old_status = UNBLANK; @@ -74,6 +120,12 @@ static void bl_trig_activate(struct led_classdev *led) ret = fb_register_client(&n->notifier); if (ret) dev_err(led->dev, "unable to register backlight trigger\n"); + + return; + +err_invert: + led->trigger_data = NULL; + kfree(n); } static void bl_trig_deactivate(struct led_classdev *led) @@ -82,6 +134,7 @@ static void bl_trig_deactivate(struct led_classdev *led) (struct bl_trig_notifier *) led->trigger_data; if (n) { + device_remove_file(led->dev, &dev_attr_inverted); fb_unregister_client(&n->notifier); kfree(n); } diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 1cec02f6c431..ade1e656bfb2 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -15,7 +15,7 @@ #define MAX_PMU_LEVEL 0xFF -static struct backlight_ops pmu_backlight_data; +static const struct backlight_ops pmu_backlight_data; static DEFINE_SPINLOCK(pmu_backlight_lock); static int sleeping, uses_pmu_bl; static u8 bl_curve[FB_BACKLIGHT_LEVELS]; @@ -115,7 +115,7 @@ static int pmu_backlight_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops pmu_backlight_data = { +static const struct backlight_ops pmu_backlight_data = { .get_brightness = pmu_backlight_get_brightness, .update_status = pmu_backlight_update_status, diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index cd29c8248386..8b021eb0d48c 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2257,7 +2257,7 @@ static int pmu_sleep_valid(suspend_state_t state) && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0); } -static struct platform_suspend_ops pmu_pm_ops = { +static const struct platform_suspend_ops pmu_pm_ops = { .enter = powerbook_sleep, .valid = pmu_sleep_valid, }; diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 2c00980acfcb..7e40035028d2 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h @@ -177,7 +177,7 @@ IN[0] - Task handle. IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, 3 = 2D H/V separable, 4 = 2D symmetric non-separable - IN[2] - chroma type: 0 - diable, 1 = 1D horizontal + IN[2] - chroma type: 0 - disable, 1 = 1D horizontal ReturnCode - One of the ERR_CAPTURE_... */ #define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c index 627926f6bde8..7eb79af28aa3 100644 --- a/drivers/media/video/cx25840/cx25840-ir.c +++ b/drivers/media/video/cx25840/cx25840-ir.c @@ -261,7 +261,7 @@ static u16 ns_to_pulse_width_count(u32 ns, u16 divider) u32 rem; /* - * The 2 lsb's of the pulse width timer count are not accessable, hence + * The 2 lsb's of the pulse width timer count are not accessible, hence * the (1 << 2) */ n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */ diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index 188841b476e0..ebd5c4338ebb 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -33,7 +33,7 @@ extern spinlock_t vpif_lock; #define regr(reg) readl((reg) + vpif_base) #define regw(value, reg) writel(value, (reg + vpif_base)) -/* Register Addresss Offsets */ +/* Register Address Offsets */ #define VPIF_PID (0x0000) #define VPIF_CH0_CTRL (0x0004) #define VPIF_CH1_CTRL (0x0008) diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c index 7918680917d0..3e5cf27ec2b2 100644 --- a/drivers/media/video/davinci/vpss.c +++ b/drivers/media/video/davinci/vpss.c @@ -85,7 +85,7 @@ enum vpss_platform_type { /* * vpss operations. Depends on platform. Not all functions are available * on all platforms. The api, first check if a functio is available before - * invoking it. In the probe, the function ptrs are intialized based on + * invoking it. In the probe, the function ptrs are initialized based on * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. */ struct vpss_hw_ops { diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 83de97ad971e..029a4babfd61 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -1286,7 +1286,7 @@ static int omap_vout_release(struct file *file) videobuf_mmap_free(q); /* Even if apply changes fails we should continue - freeing allocated memeory */ + freeing allocated memory */ if (vout->streaming) { u32 mask = 0; diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index d6bf3f82cc34..58af67f2278b 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c @@ -655,8 +655,8 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) goto out; } - /* Check that the hardware is accessable. If the status bytes are - * 0xFF then the device is not accessable, the the IRQ belongs + /* Check that the hardware is accessible. If the status bytes are + * 0xFF then the device is not accessible, the the IRQ belongs * to another driver. * 4 x u32 interrupt registers. */ diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h index 494957b10bac..7f38549715b6 100644 --- a/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h @@ -147,7 +147,7 @@ enum sn9c102_i2c_interface { struct sn9c102_sensor { char name[32], /* sensor name */ - maintainer[64]; /* name of the mantainer <email> */ + maintainer[64]; /* name of the maintainer <email> */ enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */ diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index e63b40f5a706..c799e4eb6fcd 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -789,7 +789,7 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, * Get the value of a TVP7002 decoder device register. * Returns zero when successful, -EINVAL if register read fails or * access to I2C client fails, -EPERM if the call is not allowed - * by diabled CAP_SYS_ADMIN. + * by disabled CAP_SYS_ADMIN. */ static int tvp7002_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index e25aca5759fb..2f973cd56408 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -13,14 +13,12 @@ #include <linux/pci.h> #include <linux/gpio.h> #include <linux/interrupt.h> -#include <linux/pci.h> #include <linux/platform_device.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-chip-ident.h> #include <media/videobuf-dma-sg.h> -#include <linux/device.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/pm_qos_params.h> diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index c00fe8253c51..e9a3eab7b0cf 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work) if (!host->card) { host->card = card; if (device_register(&card->dev)) { + put_device(&card->dev); kfree(host->card); host->card = NULL; } @@ -510,14 +511,18 @@ int memstick_add_host(struct memstick_host *host) { int rc; - if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL)) - return -ENOMEM; + while (1) { + if (!idr_pre_get(&memstick_host_idr, GFP_KERNEL)) + return -ENOMEM; - spin_lock(&memstick_host_lock); - rc = idr_get_new(&memstick_host_idr, host, &host->id); - spin_unlock(&memstick_host_lock); - if (rc) - return rc; + spin_lock(&memstick_host_lock); + rc = idr_get_new(&memstick_host_idr, host, &host->id); + spin_unlock(&memstick_host_lock); + if (!rc) + break; + else if (rc != -EAGAIN) + return rc; + } dev_set_name(&host->dev, "memstick%u", host->id); diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 02362eccc588..57b42bfc7d23 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -23,7 +23,6 @@ #define DRIVER_NAME "mspro_block" -static DEFINE_MUTEX(mspro_block_mutex); static int major; module_param(major, int, 0644); @@ -160,6 +159,13 @@ struct mspro_block_data { int (*mrq_handler)(struct memstick_dev *card, struct memstick_request **mrq); + + /* Default request setup function for data access method preferred by + * this host instance. + */ + void (*setup_transfer)(struct memstick_dev *card, + u64 offset, size_t length); + struct attribute_group attr_group; struct scatterlist req_sg[MSPRO_BLOCK_MAX_SEGS]; @@ -181,7 +187,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) struct mspro_block_data *msb = disk->private_data; int rc = -ENXIO; - mutex_lock(&mspro_block_mutex); mutex_lock(&mspro_block_disk_lock); if (msb && msb->card) { @@ -193,7 +198,6 @@ static int mspro_block_bd_open(struct block_device *bdev, fmode_t mode) } mutex_unlock(&mspro_block_disk_lock); - mutex_unlock(&mspro_block_mutex); return rc; } @@ -225,11 +229,7 @@ static int mspro_block_disk_release(struct gendisk *disk) static int mspro_block_bd_release(struct gendisk *disk, fmode_t mode) { - int ret; - mutex_lock(&mspro_block_mutex); - ret = mspro_block_disk_release(disk); - mutex_unlock(&mspro_block_mutex); - return ret; + return mspro_block_disk_release(disk); } static int mspro_block_bd_getgeo(struct block_device *bdev, @@ -663,14 +663,43 @@ has_int_reg: } } +/*** Transfer setup functions for different access methods. ***/ + +/** Setup data transfer request for SET_CMD TPC with arguments in card + * registers. + * + * @card Current media instance + * @offset Target data offset in bytes + * @length Required transfer length in bytes. + */ +static void h_mspro_block_setup_cmd(struct memstick_dev *card, u64 offset, + size_t length) +{ + struct mspro_block_data *msb = memstick_get_drvdata(card); + struct mspro_param_register param = { + .system = msb->system, + .data_count = cpu_to_be16((uint16_t)(length / msb->page_size)), + /* ISO C90 warning precludes direct initialization for now. */ + .data_address = 0, + .tpc_param = 0 + }; + + do_div(offset, msb->page_size); + param.data_address = cpu_to_be32((uint32_t)offset); + + card->next_request = h_mspro_block_req_init; + msb->mrq_handler = h_mspro_block_transfer_data; + memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, + ¶m, sizeof(param)); +} + /*** Data transfer ***/ static int mspro_block_issue_req(struct memstick_dev *card, int chunk) { struct mspro_block_data *msb = memstick_get_drvdata(card); - sector_t t_sec; + u64 t_off; unsigned int count; - struct mspro_param_register param; try_again: while (chunk) { @@ -685,30 +714,17 @@ try_again: continue; } - t_sec = blk_rq_pos(msb->block_req) << 9; - sector_div(t_sec, msb->page_size); - + t_off = blk_rq_pos(msb->block_req); + t_off <<= 9; count = blk_rq_bytes(msb->block_req); - count /= msb->page_size; - param.system = msb->system; - param.data_count = cpu_to_be16(count); - param.data_address = cpu_to_be32((uint32_t)t_sec); - param.tpc_param = 0; + msb->setup_transfer(card, t_off, count); msb->data_dir = rq_data_dir(msb->block_req); msb->transfer_cmd = msb->data_dir == READ ? MSPRO_CMD_READ_DATA : MSPRO_CMD_WRITE_DATA; - dev_dbg(&card->dev, "data transfer: cmd %x, " - "lba %x, count %x\n", msb->transfer_cmd, - be32_to_cpu(param.data_address), count); - - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - ¶m, sizeof(param)); memstick_new_req(card->host); return 0; } @@ -963,18 +979,16 @@ try_again: static int mspro_block_read_attributes(struct memstick_dev *card) { struct mspro_block_data *msb = memstick_get_drvdata(card); - struct mspro_param_register param = { - .system = msb->system, - .data_count = cpu_to_be16(1), - .data_address = 0, - .tpc_param = 0 - }; struct mspro_attribute *attr = NULL; struct mspro_sys_attr *s_attr = NULL; unsigned char *buffer = NULL; int cnt, rc, attr_count; - unsigned int addr; - unsigned short page_count; + /* While normally physical device offsets, represented here by + * attr_offset and attr_len will be of large numeric types, we can be + * sure, that attributes are close enough to the beginning of the + * device, to save ourselves some trouble. + */ + unsigned int addr, attr_offset = 0, attr_len = msb->page_size; attr = kmalloc(msb->page_size, GFP_KERNEL); if (!attr) @@ -987,10 +1001,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, ¶m, - sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); + memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1021,13 +1033,12 @@ static int mspro_block_read_attributes(struct memstick_dev *card) } msb->attr_group.name = "media_attributes"; - buffer = kmalloc(msb->page_size, GFP_KERNEL); + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } - memcpy(buffer, (char *)attr, msb->page_size); - page_count = 1; + memcpy(buffer, (char *)attr, attr_len); for (cnt = 0; cnt < attr_count; ++cnt) { s_attr = kzalloc(sizeof(struct mspro_sys_attr), GFP_KERNEL); @@ -1038,9 +1049,10 @@ static int mspro_block_read_attributes(struct memstick_dev *card) msb->attr_group.attrs[cnt] = &s_attr->dev_attr.attr; addr = be32_to_cpu(attr->entries[cnt].address); - rc = be32_to_cpu(attr->entries[cnt].size); + s_attr->size = be32_to_cpu(attr->entries[cnt].size); dev_dbg(&card->dev, "adding attribute %d: id %x, address %x, " - "size %x\n", cnt, attr->entries[cnt].id, addr, rc); + "size %zx\n", cnt, attr->entries[cnt].id, addr, + s_attr->size); s_attr->id = attr->entries[cnt].id; if (mspro_block_attr_name(s_attr->id)) snprintf(s_attr->name, sizeof(s_attr->name), "%s", @@ -1054,57 +1066,47 @@ static int mspro_block_read_attributes(struct memstick_dev *card) s_attr->dev_attr.attr.mode = S_IRUGO; s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id); - if (!rc) + if (!s_attr->size) continue; - s_attr->size = rc; - s_attr->data = kmalloc(rc, GFP_KERNEL); + s_attr->data = kmalloc(s_attr->size, GFP_KERNEL); if (!s_attr->data) { rc = -ENOMEM; goto out_free_buffer; } - if (((addr / msb->page_size) - == be32_to_cpu(param.data_address)) - && (((addr + rc - 1) / msb->page_size) - == be32_to_cpu(param.data_address))) { + if (((addr / msb->page_size) == (attr_offset / msb->page_size)) + && (((addr + s_attr->size - 1) / msb->page_size) + == (attr_offset / msb->page_size))) { memcpy(s_attr->data, buffer + addr % msb->page_size, - rc); + s_attr->size); continue; } - if (page_count <= (rc / msb->page_size)) { + attr_offset = (addr / msb->page_size) * msb->page_size; + + if ((attr_offset + attr_len) < (addr + s_attr->size)) { kfree(buffer); - page_count = (rc / msb->page_size) + 1; - buffer = kmalloc(page_count * msb->page_size, - GFP_KERNEL); + attr_len = (((addr + s_attr->size) / msb->page_size) + + 1 ) * msb->page_size - attr_offset; + buffer = kmalloc(attr_len, GFP_KERNEL); if (!buffer) { rc = -ENOMEM; goto out_free_attr; } } - param.system = msb->system; - param.data_count = cpu_to_be16((rc / msb->page_size) + 1); - param.data_address = cpu_to_be32(addr / msb->page_size); - param.tpc_param = 0; - - sg_init_one(&msb->req_sg[0], buffer, - be16_to_cpu(param.data_count) * msb->page_size); + sg_init_one(&msb->req_sg[0], buffer, attr_len); msb->seg_count = 1; msb->current_seg = 0; msb->current_page = 0; msb->data_dir = READ; msb->transfer_cmd = MSPRO_CMD_READ_ATRB; - dev_dbg(&card->dev, "reading attribute pages %x, %x\n", - be32_to_cpu(param.data_address), - be16_to_cpu(param.data_count)); + dev_dbg(&card->dev, "reading attribute range %x, %x\n", + attr_offset, attr_len); - card->next_request = h_mspro_block_req_init; - msb->mrq_handler = h_mspro_block_transfer_data; - memstick_init_req(&card->current_mrq, MS_TPC_WRITE_REG, - (char *)¶m, sizeof(param)); + msb->setup_transfer(card, attr_offset, attr_len); memstick_new_req(card->host); wait_for_completion(&card->mrq_complete); if (card->current_mrq.error) { @@ -1112,7 +1114,8 @@ static int mspro_block_read_attributes(struct memstick_dev *card) goto out_free_buffer; } - memcpy(s_attr->data, buffer + addr % msb->page_size, rc); + memcpy(s_attr->data, buffer + addr % msb->page_size, + s_attr->size); } rc = 0; @@ -1130,6 +1133,8 @@ static int mspro_block_init_card(struct memstick_dev *card) int rc = 0; msb->system = MEMSTICK_SYS_SERIAL; + msb->setup_transfer = h_mspro_block_setup_cmd; + card->reg_addr.r_offset = offsetof(struct mspro_register, status); card->reg_addr.r_length = sizeof(struct ms_status_register); card->reg_addr.w_offset = offsetof(struct mspro_register, param); @@ -1206,10 +1211,12 @@ static int mspro_block_init_disk(struct memstick_dev *card) msb->page_size = be16_to_cpu(sys_info->unit_size); - if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) + mutex_lock(&mspro_block_disk_lock); + if (!idr_pre_get(&mspro_block_disk_idr, GFP_KERNEL)) { + mutex_unlock(&mspro_block_disk_lock); return -ENOMEM; + } - mutex_lock(&mspro_block_disk_lock); rc = idr_get_new(&mspro_block_disk_idr, card, &disk_id); mutex_unlock(&mspro_block_disk_lock); diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index f2b894cd8b02..d89d925caecf 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -61,6 +61,7 @@ struct jmb38x_ms_host { struct memstick_request *req; unsigned char cmd_flags; unsigned char io_pos; + unsigned char ifmode; unsigned int io_word[2]; }; @@ -136,15 +137,14 @@ struct jmb38x_ms { #define PAD_PU_PD_ON_MS_SOCK0 0x5f8f0000 #define PAD_PU_PD_ON_MS_SOCK1 0x0f0f0000 +#define CLOCK_CONTROL_BY_MMIO 0x00000008 #define CLOCK_CONTROL_40MHZ 0x00000001 -#define CLOCK_CONTROL_50MHZ 0x0000000a -#define CLOCK_CONTROL_60MHZ 0x00000008 -#define CLOCK_CONTROL_62_5MHZ 0x0000000c +#define CLOCK_CONTROL_50MHZ 0x00000002 +#define CLOCK_CONTROL_60MHZ 0x00000010 +#define CLOCK_CONTROL_62_5MHZ 0x00000004 #define CLOCK_CONTROL_OFF 0x00000000 #define PCI_CTL_CLOCK_DLY_ADDR 0x000000b0 -#define PCI_CTL_CLOCK_DLY_MASK_A 0x00000f00 -#define PCI_CTL_CLOCK_DLY_MASK_B 0x0000f000 enum { CMD_READY = 0x01, @@ -390,8 +390,13 @@ static int jmb38x_ms_issue_cmd(struct memstick_host *msh) if (host->req->data_dir == READ) cmd |= TPC_DIR; - if (host->req->need_card_int) - cmd |= TPC_WAIT_INT; + + if (host->req->need_card_int) { + if (host->ifmode == MEMSTICK_SERIAL) + cmd |= TPC_GET_INT; + else + cmd |= TPC_WAIT_INT; + } data = host->req->data; @@ -529,7 +534,10 @@ static irqreturn_t jmb38x_ms_isr(int irq, void *dev_id) if (irq_status & INT_STATUS_ANY_ERR) { if (irq_status & INT_STATUS_CRC_ERR) host->req->error = -EILSEQ; - else + else if (irq_status & INT_STATUS_TPC_ERR) { + dev_dbg(&host->chip->pdev->dev, "TPC_ERR\n"); + jmb38x_ms_complete_cmd(msh, 0); + } else host->req->error = -ETIME; } else { if (host->cmd_flags & DMA_DATA) { @@ -644,7 +652,6 @@ static int jmb38x_ms_reset(struct jmb38x_ms_host *host) ndelay(20); } dev_dbg(&host->chip->pdev->dev, "reset_req timeout\n"); - /* return -EIO; */ reset_next: writel(HOST_CONTROL_RESET | HOST_CONTROL_CLOCK_EN @@ -675,7 +682,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, { struct jmb38x_ms_host *host = memstick_priv(msh); unsigned int host_ctl = readl(host->addr + HOST_CONTROL); - unsigned int clock_ctl = CLOCK_CONTROL_40MHZ, clock_delay = 0; + unsigned int clock_ctl = CLOCK_CONTROL_BY_MMIO, clock_delay = 0; int rc = 0; switch (param) { @@ -687,9 +694,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, host_ctl = 7; host_ctl |= HOST_CONTROL_POWER_EN - | HOST_CONTROL_CLOCK_EN - | HOST_CONTROL_HW_OC_P - | HOST_CONTROL_TDELAY_EN; + | HOST_CONTROL_CLOCK_EN; writel(host_ctl, host->addr + HOST_CONTROL); writel(host->id ? PAD_PU_PD_ON_MS_SOCK1 @@ -712,46 +717,88 @@ static int jmb38x_ms_set_param(struct memstick_host *msh, return -EINVAL; break; case MEMSTICK_INTERFACE: + dev_dbg(&host->chip->pdev->dev, + "Set Host Interface Mode to %d\n", value); + host_ctl &= ~(HOST_CONTROL_FAST_CLK | HOST_CONTROL_REI | + HOST_CONTROL_REO); + host_ctl |= HOST_CONTROL_TDELAY_EN | HOST_CONTROL_HW_OC_P; host_ctl &= ~(3 << HOST_CONTROL_IF_SHIFT); - pci_read_config_dword(host->chip->pdev, - PCI_CTL_CLOCK_DLY_ADDR, - &clock_delay); - clock_delay &= host->id ? ~PCI_CTL_CLOCK_DLY_MASK_B - : ~PCI_CTL_CLOCK_DLY_MASK_A; if (value == MEMSTICK_SERIAL) { - host_ctl &= ~HOST_CONTROL_FAST_CLK; - host_ctl &= ~HOST_CONTROL_REO; host_ctl |= HOST_CONTROL_IF_SERIAL << HOST_CONTROL_IF_SHIFT; host_ctl |= HOST_CONTROL_REI; - clock_ctl = CLOCK_CONTROL_40MHZ; + clock_ctl |= CLOCK_CONTROL_40MHZ; + clock_delay = 0; } else if (value == MEMSTICK_PAR4) { - host_ctl |= HOST_CONTROL_FAST_CLK | HOST_CONTROL_REO; + host_ctl |= HOST_CONTROL_FAST_CLK; host_ctl |= HOST_CONTROL_IF_PAR4 << HOST_CONTROL_IF_SHIFT; - host_ctl &= ~HOST_CONTROL_REI; - clock_ctl = CLOCK_CONTROL_40MHZ; - clock_delay |= host->id ? (4 << 12) : (4 << 8); + host_ctl |= HOST_CONTROL_REO; + clock_ctl |= CLOCK_CONTROL_40MHZ; + clock_delay = 4; } else if (value == MEMSTICK_PAR8) { host_ctl |= HOST_CONTROL_FAST_CLK; host_ctl |= HOST_CONTROL_IF_PAR8 << HOST_CONTROL_IF_SHIFT; - host_ctl &= ~(HOST_CONTROL_REI | HOST_CONTROL_REO); - clock_ctl = CLOCK_CONTROL_50MHZ; + clock_ctl |= CLOCK_CONTROL_50MHZ; + clock_delay = 0; } else return -EINVAL; writel(host_ctl, host->addr + HOST_CONTROL); + writel(CLOCK_CONTROL_OFF, host->addr + CLOCK_CONTROL); writel(clock_ctl, host->addr + CLOCK_CONTROL); - pci_write_config_dword(host->chip->pdev, - PCI_CTL_CLOCK_DLY_ADDR, - clock_delay); + pci_write_config_byte(host->chip->pdev, + PCI_CTL_CLOCK_DLY_ADDR + 1, + clock_delay); + host->ifmode = value; break; }; return 0; } +#define PCI_PMOS0_CONTROL 0xae +#define PMOS0_ENABLE 0x01 +#define PMOS0_OVERCURRENT_LEVEL_2_4V 0x06 +#define PMOS0_EN_OVERCURRENT_DEBOUNCE 0x40 +#define PMOS0_SW_LED_POLARITY_ENABLE 0x80 +#define PMOS0_ACTIVE_BITS (PMOS0_ENABLE | PMOS0_EN_OVERCURRENT_DEBOUNCE | \ + PMOS0_OVERCURRENT_LEVEL_2_4V) +#define PCI_PMOS1_CONTROL 0xbd +#define PMOS1_ACTIVE_BITS 0x4a +#define PCI_CLOCK_CTL 0xb9 + +static int jmb38x_ms_pmos(struct pci_dev *pdev, int flag) +{ + unsigned char val; + + pci_read_config_byte(pdev, PCI_PMOS0_CONTROL, &val); + if (flag) + val |= PMOS0_ACTIVE_BITS; + else + val &= ~PMOS0_ACTIVE_BITS; + pci_write_config_byte(pdev, PCI_PMOS0_CONTROL, val); + dev_dbg(&pdev->dev, "JMB38x: set PMOS0 val 0x%x\n", val); + + if (pci_resource_flags(pdev, 1)) { + pci_read_config_byte(pdev, PCI_PMOS1_CONTROL, &val); + if (flag) + val |= PMOS1_ACTIVE_BITS; + else + val &= ~PMOS1_ACTIVE_BITS; + pci_write_config_byte(pdev, PCI_PMOS1_CONTROL, val); + dev_dbg(&pdev->dev, "JMB38x: set PMOS1 val 0x%x\n", val); + } + + pci_read_config_byte(pdev, PCI_CLOCK_CTL, &val); + pci_write_config_byte(pdev, PCI_CLOCK_CTL, val & ~0x0f); + pci_write_config_byte(pdev, PCI_CLOCK_CTL, val | 0x01); + dev_dbg(&pdev->dev, "Clock Control by PCI config is disabled!\n"); + + return 0; +} + #ifdef CONFIG_PM static int jmb38x_ms_suspend(struct pci_dev *dev, pm_message_t state) @@ -784,8 +831,7 @@ static int jmb38x_ms_resume(struct pci_dev *dev) return rc; pci_set_master(dev); - pci_read_config_dword(dev, 0xac, &rc); - pci_write_config_dword(dev, 0xac, rc | 0x00470000); + jmb38x_ms_pmos(dev, 1); for (rc = 0; rc < jm->host_cnt; ++rc) { if (!jm->hosts[rc]) @@ -894,8 +940,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev, goto err_out; } - pci_read_config_dword(pdev, 0xac, &rc); - pci_write_config_dword(pdev, 0xac, rc | 0x00470000); + jmb38x_ms_pmos(pdev, 1); cnt = jmb38x_ms_count_slots(pdev); if (!cnt) { @@ -976,6 +1021,8 @@ static void jmb38x_ms_remove(struct pci_dev *dev) jmb38x_ms_free_host(jm->hosts[cnt]); } + jmb38x_ms_pmos(dev, 0); + pci_set_drvdata(dev, NULL); pci_release_regions(dev); pci_disable_device(dev); @@ -983,8 +1030,9 @@ static void jmb38x_ms_remove(struct pci_dev *dev) } static struct pci_device_id jmb38x_ms_id_tbl [] = { - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0 }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_MS) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB385_MS) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB390_MS) }, { } }; diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index 691620dbedd2..8b04810df469 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -268,7 +268,7 @@ /* Compatibility Error : IR Disabled */ #define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030) -/* Compatibility Error : Inquiry Comand failed */ +/* Compatibility Error : Inquiry Command failed */ #define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031) /* Compatibility Error : Device not direct access device */ #define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 3e57b61ca446..3358c0af3466 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -7977,7 +7977,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) NULL, /* 2Eh */ NULL, /* 2Fh */ "Compatibility Error: IR Disabled", /* 30h */ - "Compatibility Error: Inquiry Comand Failed", /* 31h */ + "Compatibility Error: Inquiry Command Failed", /* 31h */ "Compatibility Error: Device not Direct Access " "Device ", /* 32h */ "Compatibility Error: Removable Device Found", /* 33h */ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index d48c2c6058e1..8aefb1829fcd 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1146,7 +1146,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, * * This function will delete scheduled target reset from the list and * try to send next target reset. This will be called from completion - * context of any Task managment command. + * context of any Task management command. */ void diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index f87a9d405a5e..ae7cad185898 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -309,7 +309,7 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq) * @ireq: I2O block request * @mptr: message body pointer * - * Builds the SG list and map it to be accessable by the controller. + * Builds the SG list and map it to be accessible by the controller. * * Returns 0 on failure or 1 on success. */ diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index b3b2aaf89dbe..8d221ba5e38d 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -218,6 +218,18 @@ static const char *wm8994_main_supplies[] = { "SPKVDD2", }; +static const char *wm8958_main_supplies[] = { + "DBVDD1", + "DBVDD2", + "DBVDD3", + "DCVDD", + "AVDD1", + "AVDD2", + "CPVDD", + "SPKVDD1", + "SPKVDD2", +}; + #ifdef CONFIG_PM static int wm8994_device_suspend(struct device *dev) { @@ -239,7 +251,7 @@ static int wm8994_device_suspend(struct device *dev) if (ret < 0) dev_err(dev, "Failed to save LDO registers: %d\n", ret); - ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + ret = regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to disable supplies: %d\n", ret); @@ -254,7 +266,7 @@ static int wm8994_device_resume(struct device *dev) struct wm8994 *wm8994 = dev_get_drvdata(dev); int ret; - ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), + ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(dev, "Failed to enable supplies: %d\n", ret); @@ -305,9 +317,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) /* * Instantiate the generic non-control parts of the device. */ -static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) +static int wm8994_device_init(struct wm8994 *wm8994, int irq) { struct wm8994_pdata *pdata = wm8994->dev->platform_data; + const char *devname; int ret, i; mutex_init(&wm8994->io_lock); @@ -323,25 +336,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) goto err; } + switch (wm8994->type) { + case WM8994: + wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); + break; + case WM8958: + wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies); + break; + default: + BUG(); + return -EINVAL; + } + wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) * - ARRAY_SIZE(wm8994_main_supplies), + wm8994->num_supplies, GFP_KERNEL); if (!wm8994->supplies) { ret = -ENOMEM; goto err; } - for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) - wm8994->supplies[i].supply = wm8994_main_supplies[i]; - - ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies), + switch (wm8994->type) { + case WM8994: + for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) + wm8994->supplies[i].supply = wm8994_main_supplies[i]; + break; + case WM8958: + for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++) + wm8994->supplies[i].supply = wm8958_main_supplies[i]; + break; + default: + BUG(); + return -EINVAL; + } + + ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); goto err_supplies; } - ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies), + ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); @@ -353,7 +389,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) dev_err(wm8994->dev, "Failed to read ID register\n"); goto err_enable; } - if (ret != 0x8994) { + switch (ret) { + case 0x8994: + devname = "WM8994"; + if (wm8994->type != WM8994) + dev_warn(wm8994->dev, "Device registered as type %d\n", + wm8994->type); + wm8994->type = WM8994; + break; + case 0x8958: + devname = "WM8958"; + if (wm8994->type != WM8958) + dev_warn(wm8994->dev, "Device registered as type %d\n", + wm8994->type); + wm8994->type = WM8958; + break; + default: dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n", ret); ret = -EINVAL; @@ -370,14 +421,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) switch (ret) { case 0: case 1: - dev_warn(wm8994->dev, "revision %c not fully supported\n", - 'A' + ret); + if (wm8994->type == WM8994) + dev_warn(wm8994->dev, + "revision %c not fully supported\n", + 'A' + ret); break; default: - dev_info(wm8994->dev, "revision %c\n", 'A' + ret); break; } + dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret); if (pdata) { wm8994->irq_base = pdata->irq_base; @@ -423,10 +476,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq) err_irq: wm8994_irq_exit(wm8994); err_enable: - regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); err_get: - regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); + regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); err_supplies: kfree(wm8994->supplies); err: @@ -439,9 +492,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994) { mfd_remove_devices(wm8994->dev); wm8994_irq_exit(wm8994); - regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies), + regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); - regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies); + regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); kfree(wm8994->supplies); kfree(wm8994); } @@ -506,8 +559,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, wm8994->read_dev = wm8994_i2c_read_device; wm8994->write_dev = wm8994_i2c_write_device; wm8994->irq = i2c->irq; + wm8994->type = id->driver_data; - return wm8994_device_init(wm8994, id->driver_data, i2c->irq); + return wm8994_device_init(wm8994, i2c->irq); } static int wm8994_i2c_remove(struct i2c_client *i2c) @@ -535,7 +589,8 @@ static int wm8994_i2c_resume(struct i2c_client *i2c) #endif static const struct i2c_device_id wm8994_i2c_id[] = { - { "wm8994", 0 }, + { "wm8994", WM8994 }, + { "wm8958", WM8958 }, { } }; MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4d073f1e4502..1e1a4be8eb6c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -402,7 +402,7 @@ config TI_DAC7512 DAC7512 16-bit digital-to-analog converter. This driver can also be built as a module. If so, the module - will be calles ti_dac7512. + will be called ti_dac7512. config VMWARE_BALLOON tristate "VMware Balloon Driver" diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c index 9e3879ef58f2..fe8616a8d287 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/misc/arm-charlcd.c @@ -313,7 +313,7 @@ static int __init charlcd_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work); schedule_delayed_work(&lcd->init_work, 0); - dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n", + dev_info(&pdev->dev, "initialized ARM character LCD at %08x\n", lcd->phybase); return 0; diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2a1e804a71aa..4d2ea8e80140 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -45,7 +45,7 @@ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.1.1-k"); +MODULE_VERSION("1.2.1.2-k"); MODULE_ALIAS("dmi:*:svnVMware*:*"); MODULE_ALIAS("vmware_vmmemctl"); MODULE_LICENSE("GPL"); @@ -315,7 +315,8 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) * fear that guest will need it. Host may reject some pages, we need to * check the return value and maybe submit a different page. */ -static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) +static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, + unsigned int *hv_status) { unsigned long status, dummy; u32 pfn32; @@ -326,7 +327,7 @@ static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) STATS_INC(b->stats.lock); - status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); + *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); if (vmballoon_check_status(b, status)) return true; @@ -410,6 +411,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) { struct page *page; gfp_t flags; + unsigned int hv_status; bool locked = false; do { @@ -429,11 +431,12 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) } /* inform monitor */ - locked = vmballoon_send_lock_page(b, page_to_pfn(page)); + locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); if (!locked) { STATS_INC(b->stats.refused_alloc); - if (b->reset_required) { + if (hv_status == VMW_BALLOON_ERROR_RESET || + hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) { __free_page(page); return -EIO; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 217f82037fc1..bfc8a8ae55df 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -257,7 +257,7 @@ static u32 get_card_status(struct mmc_card *card, struct request *req) cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) - printk(KERN_ERR "%s: error %d sending status comand", + printk(KERN_ERR "%s: error %d sending status command", req->rq_disk->disk_name, err); return cmd.resp[0]; } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index c22a4c039988..afe8c6fa166a 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -501,7 +501,7 @@ config MMC_SH_MMCIF tristate "SuperH Internal MMCIF support" depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE) help - This selects the MMC Host Interface controler (MMCIF). + This selects the MMC Host Interface controller (MMCIF). This driver supports MMCIF in sh7724/sh7757/sh7372. diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 41e5a60493ad..ef72e874ca36 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -192,7 +192,7 @@ static inline void SEND_STOP(struct au1xmmc_host *host) au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host)); au_sync(); - /* Send the stop commmand */ + /* Send the stop command */ au_writel(STOP_CMD, HOST_CMD(host)); } diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index f472c2714eb8..bbc298fd2a15 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -446,7 +446,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, mmc->max_seg_size = 1024 * 512; mmc->max_blk_size = 512; - /* reset the controler */ + /* reset the controller */ if (sdricoh_reset(host)) { dev_dbg(dev, "could not reset\n"); result = -EIO; @@ -478,7 +478,7 @@ static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev) dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device" " %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]); - /* search pci cardbus bridge that contains the mmc controler */ + /* search pci cardbus bridge that contains the mmc controller */ /* the io region is already claimed by yenta_socket... */ while ((pci_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index f511dd15fd31..ee4bb3330bdf 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1134,7 +1134,7 @@ static const struct file_operations mtd_fops = { static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); + return mount_pseudo(fs_type, "mtd_inode:", NULL, NULL, MTD_INODE_FS_MAGIC); } static struct file_system_type mtd_inodefs_type = { diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 1ee72f3f0512..c948150079be 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -307,6 +307,11 @@ static void mtdoops_do_dump(struct kmsg_dumper *dumper, unsigned long l1_cpy, l2_cpy; char *dst; + if (reason != KMSG_DUMP_OOPS && + reason != KMSG_DUMP_PANIC && + reason != KMSG_DUMP_KEXEC) + return; + /* Only dump oopses if dump_oops is set */ if (reason == KMSG_DUMP_OOPS && !dump_oops) return; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1f75a1b1f7c3..31bf376b82a0 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -821,7 +821,7 @@ retry: * * Wait for command done. This is a helper function for nand_wait used when * we are in interrupt context. May happen when in panic and trying to write - * an oops trough mtdoops. + * an oops through mtdoops. */ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, unsigned long timeo) diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 6a858a29db56..a6cd335c9436 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1415,12 +1415,12 @@ struct bnx2x_func_init_params { else /* skip rx queue - * if FCOE l2 support is diabled and this is the fcoe L2 queue + * if FCOE l2 support is disabled and this is the fcoe L2 queue */ #define skip_rx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) /* skip tx queue - * if FCOE l2 support is diabled and this is the fcoe L2 queue + * if FCOE l2 support is disabled and this is the fcoe L2 queue */ #define skip_tx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 84e1af4d65e1..8cdcf5b39d1e 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -5037,7 +5037,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code) memset(&ilt_cli, 0, sizeof(struct ilt_client_info)); memset(&ilt, 0, sizeof(struct bnx2x_ilt)); - /* initalize dummy TM client */ + /* initialize dummy TM client */ ilt_cli.start = 0; ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1; ilt_cli.client_num = ILT_CLIENT_TM; diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 38ef7ca9f21d..c939683e3d61 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -1633,7 +1633,7 @@ (~misc_registers_sw_timer_cfg_4.sw_timer_cfg_4[1] ) is set */ #define MISC_REG_SW_TIMER_RELOAD_VAL_4 0xa2fc /* [RW 32] the value of the counter for sw timers1-8. there are 8 addresses - in this register. addres 0 - timer 1; address 1 - timer 2, ... address 7 - + in this register. address 0 - timer 1; address 1 - timer 2, ... address 7 - timer 8 */ #define MISC_REG_SW_TIMER_VAL 0xa5c0 /* [RW 1] Set by the MCP to remember if one or more of the drivers is/are diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 48cf24ff4e6f..171782e2bb39 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -840,7 +840,7 @@ static int ad_lacpdu_send(struct port *port) lacpdu_header = (struct lacpdu_header *)skb_put(skb, length); memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); - /* Note: source addres is set to be the member's PERMANENT address, + /* Note: source address is set to be the member's PERMANENT address, because we use it to identify loopback lacpdus in receive. */ memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU; @@ -881,7 +881,7 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) marker_header = (struct bond_marker_header *)skb_put(skb, length); memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); - /* Note: source addres is set to be the member's PERMANENT address, + /* Note: source address is set to be the member's PERMANENT address, because we use it to identify loopback MARKERs in receive. */ memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); marker_header->hdr.h_proto = PKT_TYPE_LACPDU; @@ -1916,7 +1916,7 @@ int bond_3ad_bind_slave(struct slave *slave) return -1; } - //check that the slave has not been intialized yet. + //check that the slave has not been initialized yet. if (SLAVE_AD_INFO(slave).port.slave != slave) { // port initialization diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 63ebf76d2390..8a43c7e19701 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -556,7 +556,7 @@ struct chelsio_vpd_t { #define EEPROM_MAX_POLL 4 /* - * Read SEEPROM. A zero is written to the flag register when the addres is + * Read SEEPROM. A zero is written to the flag register when the address is * written to the Control register. The hardware device will set the flag to a * one when 4B have been transferred to the Data register. */ diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c index a8766fb2f9ab..e13b7fe9d082 100644 --- a/drivers/net/cxgb3/mc5.c +++ b/drivers/net/cxgb3/mc5.c @@ -318,7 +318,7 @@ static void mc5_dbgi_mode_disable(const struct mc5 *mc5) /* * Initialization that requires the OS and protocol layers to already - * be intialized goes here. + * be initialized goes here. */ int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters, unsigned int nroutes) diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index ec8579a0a808..d55db6b38e7b 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -607,7 +607,7 @@ struct t3_vpd { * * Read a 32-bit word from a location in VPD EEPROM using the card's PCI * VPD ROM capability. A zero is written to the flag bit when the - * addres is written to the control register. The hardware device will + * address is written to the control register. The hardware device will * set the flag to 1 when 4 bytes have been read into the data register. */ int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index f5514a0d5be6..196eeda2dd6c 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -41,7 +41,7 @@ struct e1000_hw; struct e1000_hw_stats; /* Enumerated types specific to the e1000 hardware */ -/* Media Access Controlers */ +/* Media Access Controllers */ typedef enum { e1000_undefined = 0, e1000_82542_rev2_0, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4ff88a683f61..de69c54301c1 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2233,7 +2233,7 @@ static void e1000_set_rx_mode(struct net_device *netdev) * addresses take precedence to avoid disabling unicast filtering * when possible. * - * RAR 0 is used for the station MAC adddress + * RAR 0 is used for the station MAC address * if there are not 14 addresses, go ahead and clear the filters */ i = 1; diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index cb6c7b1c1fb8..1397da118f0d 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -328,7 +328,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) /* * Ensure that the inter-port SWSM.SMBI lock bit is clear before - * first NVM or PHY acess. This should be done for single-port + * first NVM or PHY access. This should be done for single-port * devices, and for one port only on dual-port devices so that * for those devices we can still use the SMBI lock to synchronize * inter-port accesses to the PHY & NVM. diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 5328a2927731..5bb65b7382db 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -321,7 +321,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) } /* - * Reset the PHY before any acccess to it. Doing so, ensures that + * Reset the PHY before any access to it. Doing so, ensures that * the PHY is in a known good state before we read/write PHY registers. * The generic reset is sufficient here, because we haven't determined * the PHY type yet. diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index a640f1c369ae..00f89e8a9fa0 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -2986,7 +2986,7 @@ s32 e1000_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data) } /** - * e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page + * e1000_get_phy_addr_for_hv_page - Get PHY address based on page * @page: page to be accessed **/ static u32 e1000_get_phy_addr_for_hv_page(u32 page) diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 4fa8d2a4aef3..eb35951a2442 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -1761,7 +1761,7 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(mem, int, NULL, 0); module_param(autodetect, int, 0); -MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base addres(es)"); +MODULE_PARM_DESC(io, "EtherExpress Pro/10 I/O base address(es)"); MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)"); MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)"); MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)"); diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h index 4dc39e5f0156..77fcf4459161 100644 --- a/drivers/net/irda/donauboe.h +++ b/drivers/net/irda/donauboe.h @@ -30,7 +30,7 @@ * or the type-DO IR port. * * IrDA chip set list from Toshiba Computer Engineering Corp. - * model method maker controler Version + * model method maker controller Version * Portege 320CT FIR,SIR Toshiba Oboe(Triangle) * Portege 3010CT FIR,SIR Toshiba Oboe(Sydney) * Portege 3015CT FIR,SIR Toshiba Oboe(Sydney) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 8d316d9cd29d..a21f5817685b 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1079,7 +1079,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) /* * The defaults in the HW for RX PB 1-7 are not zero and so should be - * intialized to zero for non DCB mode otherwise actual total RX PB + * initialized to zero for non DCB mode otherwise actual total RX PB * would be bigger than programmed and filter space would run into * the PB 0 region. */ @@ -1167,7 +1167,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) /* * The defaults in the HW for RX PB 1-7 are not zero and so should be - * intialized to zero for non DCB mode otherwise actual total RX PB + * initialized to zero for non DCB mode otherwise actual total RX PB * would be bigger than programmed and filter space would run into * the PB 0 region. */ diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index 183765cb7f25..f35554d11441 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -238,7 +238,7 @@ static int temac_dma_bd_init(struct net_device *ndev) goto out; } /* allocate the tx and rx ring buffer descriptors. */ - /* returns a virtual addres and a physical address. */ + /* returns a virtual address and a physical address. */ lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent, sizeof(*lp->tx_bd_v) * TX_BD_NUM, &lp->tx_bd_p, GFP_KERNEL); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 581836867098..5976d1d51df1 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -36,7 +36,7 @@ Rev 1.07.06 Nov. 7 2000 Jeff Garzik <jgarzik@pobox.com> some bug fix and cleaning Rev 1.07.05 Nov. 6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support - Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaround rule + Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalizer workaround rule Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1 Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@pobox.com> softnet and init for kernel 2.4 diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 296000bf5a25..3397618d4d96 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -12,7 +12,7 @@ /* * RX HW/SW interaction overview * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * There are 2 types of RX communication channels betwean driver and NIC. + * There are 2 types of RX communication channels between driver and NIC. * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds * info about buffer's location, size and ID. An ID field is used to identify a @@ -821,7 +821,7 @@ static void bdx_setmulti(struct net_device *ndev) } /* use PMF to accept first MAC_MCST_NUM (15) addresses */ - /* TBD: sort addreses and write them in ascending order + /* TBD: sort addresses and write them in ascending order * into RX_MAC_MCST regs. we skip this phase now and accept ALL * multicast frames throu IMF */ /* accept the rest of addresses throu IMF */ @@ -1346,7 +1346,7 @@ static void print_rxfd(struct rxf_desc *rxfd) /* * TX HW/SW interaction overview * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * There are 2 types of TX communication channels betwean driver and NIC. + * There are 2 types of TX communication channels between driver and NIC. * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets * 2) TX Data Fifo - TXD - holds descriptors of full buffers. * diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 7599c457abd1..b100bd50a0d7 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1309,7 +1309,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, break; case SIOCGIFHWADDR: - /* Get hw addres */ + /* Get hw address */ memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); ifr.ifr_hwaddr.sa_family = tun->dev->type; if (copy_to_user(argp, &ifr, ifreq_len)) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index cab96ad49e60..09cac704fdd7 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -898,7 +898,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) set_mii_flow_control(vptr); /* - Check if new status is consisent with current status + Check if new status is consistent with current status if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) || (mii_status==curr_status)) { vptr->mii_status=mii_check_media_mode(vptr->mac_regs); diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 8c3103fb6442..d48486d6afa1 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -1695,7 +1695,7 @@ struct vxge_hw_device_stats_sw_err { * struct vxge_hw_device_stats - Contains HW per-device statistics, * including hw. * @devh: HW device handle. - * @dma_addr: DMA addres of the %hw_info. Given to device to fill-in the stats. + * @dma_addr: DMA address of the %hw_info. Given to device to fill-in the stats. * @hw_info_dmah: DMA handle used to map hw statistics onto the device memory * space. * @hw_info_dma_acch: One more DMA handle used subsequently to free the diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 34cff6ce6d27..4578e5b4b411 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -125,7 +125,7 @@ static u32 dscc4_pci_config_store[16]; /* Module parameters */ MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>"); -MODULE_DESCRIPTION("Siemens PEB20534 PCI Controler"); +MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller"); MODULE_LICENSE("GPL"); module_param(debug, int, 0); MODULE_PARM_DESC(debug,"Enable/disable extra messages"); diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index f0603327aafa..65bc334ed57b 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -232,7 +232,7 @@ int i2400m_check_mac_addr(struct i2400m *i2400m) result); goto error; } - /* Extract MAC addresss */ + /* Extract MAC address */ ddi = (void *) skb->data; BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address)); d_printf(2, dev, "GET DEVICE INFO: mac addr %pM\n", diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 17ecaa41a807..030cbfd31704 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -186,7 +186,7 @@ enum { * struct i2400m_poke_table - Hardware poke table for the Intel 2400m * * This structure will be used to create a device specific poke table - * to put the device in a consistant state at boot time. + * to put the device in a consistent state at boot time. * * @address: The device address to poke * @@ -703,7 +703,7 @@ enum i2400m_bm_cmd_flags { * @I2400M_BRI_MAC_REINIT: We need to reinitialize the boot * rom after reading the MAC address. This is quite a dirty hack, * if you ask me -- the device requires the bootrom to be - * intialized after reading the MAC address. + * initialized after reading the MAC address. */ enum i2400m_bri { I2400M_BRI_SOFT = 1 << 1, diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 7ad05d401ab5..fd14b9103951 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -1064,7 +1064,7 @@ /* * EEPROM command register */ -#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ +#define AR5K_EEPROM_CMD 0x6008 /* Register Address */ #define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ #define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ #define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ @@ -1084,7 +1084,7 @@ /* * EEPROM config register */ -#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */ +#define AR5K_EEPROM_CFG 0x6010 /* Register Address */ #define AR5K_EEPROM_CFG_SIZE 0x00000003 /* Size determination override */ #define AR5K_EEPROM_CFG_SIZE_AUTO 0 #define AR5K_EEPROM_CFG_SIZE_4KBIT 1 @@ -1126,7 +1126,7 @@ * Second station id register (Upper 16 bits of MAC address + PCU settings) */ #define AR5K_STA_ID1 0x8004 /* Register Address */ -#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC address */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 0dc33b65e86b..be4828167012 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -1919,7 +1919,7 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); } -/* Intialize B/G PHY power control */ +/* Initialize B/G PHY power control */ static void b43_phy_init_pctl(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 35033dd342ce..28e477d01587 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -153,7 +153,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) phy->calibrated = 1; } -/* intialize B PHY power control +/* initialize B PHY power control * as described in http://bcm-specs.sipsolutions.net/InitPowerControl */ static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index a5dbfea1bfad..b5cb3be0eb4b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -197,7 +197,7 @@ static irqreturn_t iwl_isr(int irq, void *data) none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq and no schedules tasklet. */ + /* only Re-enable if disabled by irq and no schedules tasklet. */ if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta) iwl_enable_interrupts(priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f13a83a7e62b..36335b1b54d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -1154,7 +1154,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); @@ -1368,7 +1368,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); } diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c index a08b4e56e6b1..bb1a742a98a0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c @@ -619,7 +619,7 @@ unplugged: none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 4776323b1eba..49493d176515 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -107,7 +107,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, /* * XXX: The MAC address in the command buffer is often changed from * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC adress + * written to the command buffer often is not the same MAC address * read from the command buffer when the command returns. This * issue has not yet been resolved and this debugging is left to * observe the problem. diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 2c8cc954d1b6..ec2c75d77cea 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -630,7 +630,7 @@ islpci_alloc_memory(islpci_private *priv) printk(KERN_DEBUG "islpci_alloc_memory\n"); #endif - /* remap the PCI device base address to accessable */ + /* remap the PCI device base address to accessible */ if (!(priv->device_base = ioremap(pci_resource_start(priv->pdev, 0), ISL38XX_PCI_MEM_SIZE))) { @@ -709,7 +709,7 @@ islpci_alloc_memory(islpci_private *priv) PCI_DMA_FROMDEVICE); if (!priv->pci_map_rx_address[counter]) { /* error mapping the buffer to device - accessable memory address */ + accessible memory address */ printk(KERN_ERR "failed to map skb DMA'able\n"); goto out_free; } @@ -773,7 +773,7 @@ islpci_free_memory(islpci_private *priv) priv->data_low_rx[counter] = NULL; } - /* Free the acces control list and the WPA list */ + /* Free the access control list and the WPA list */ prism54_acl_clean(&priv->acl); prism54_wpa_bss_ie_clean(priv); mgt_clean(priv); diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 2fc52bc2d7dd..d44f8e20cce0 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -450,7 +450,7 @@ islpci_eth_receive(islpci_private *priv) MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); if (unlikely(!priv->pci_map_rx_address[index])) { - /* error mapping the buffer to device accessable memory address */ + /* error mapping the buffer to device accessible memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 658542d2efe1..f3da051df39e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -273,7 +273,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, intf->beacon = entry; /* - * The MAC adddress must be configured after the device + * The MAC address must be configured after the device * has been initialized. Otherwise the device can reset * the MAC registers. * The BSSID address must only be configured in AP mode, diff --git a/drivers/net/wireless/wl1251/acx.h b/drivers/net/wireless/wl1251/acx.h index e54b21a4f8b1..efcc3aaca14f 100644 --- a/drivers/net/wireless/wl1251/acx.h +++ b/drivers/net/wireless/wl1251/acx.h @@ -1272,10 +1272,10 @@ struct wl1251_acx_tid_cfg { /* OBSOLETE */ #define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6) -/* Trace meassge on MBOX #A */ +/* Trace message on MBOX #A */ #define WL1251_ACX_INTR_TRACE_A BIT(7) -/* Trace meassge on MBOX #B */ +/* Trace message on MBOX #B */ #define WL1251_ACX_INTR_TRACE_B BIT(8) /* Command processing completion */ diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index 13fbeeccf609..c0ce2c8b43b8 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -419,7 +419,7 @@ void wl1251_disable_interrupts(struct wl1251 *wl); #define WL1251_FW_NAME "wl1251-fw.bin" #define WL1251_NVS_NAME "wl1251-nvs.bin" -#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */ +#define WL1251_POWER_ON_SLEEP 10 /* in milliseconds */ #define WL1251_PART_DOWN_MEM_START 0x0 #define WL1251_PART_DOWN_MEM_SIZE 0x16800 diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index 9cbc3f40c8dd..7bd8e4db4a71 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -47,9 +47,9 @@ #define WL1271_ACX_INTR_HW_AVAILABLE BIT(5) /* The MISC bit is used for aggregation of RX, TxComplete and TX rate update */ #define WL1271_ACX_INTR_DATA BIT(6) -/* Trace meassge on MBOX #A */ +/* Trace message on MBOX #A */ #define WL1271_ACX_INTR_TRACE_A BIT(7) -/* Trace meassge on MBOX #B */ +/* Trace message on MBOX #B */ #define WL1271_ACX_INTR_TRACE_B BIT(8) #define WL1271_ACX_INTR_ALL 0xFFFFFFFF diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index ce3d31f98c55..9050dd9b62d2 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -416,8 +416,8 @@ int wl1271_plt_stop(struct wl1271 *wl); /* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power on in case is has been shut down shortly before */ -#define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ -#define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ +#define WL1271_PRE_POWER_ON_SLEEP 20 /* in milliseconds */ +#define WL1271_POWER_ON_SLEEP 200 /* in milliseconds */ /* Macros to handle wl1271.sta_rate_set */ #define HW_BG_RATES_MASK 0xffff diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index ee82df62e646..3e5befe4d03b 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -192,7 +192,7 @@ static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) } /* - * Get Ethernet MAC addresss. + * Get Ethernet MAC address. * * WARNING: We switch to FPAGE0 and switc back again. * Making sure there is no other WL function beening called by ISR. diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig new file mode 100644 index 000000000000..ffedfd492754 --- /dev/null +++ b/drivers/nfc/Kconfig @@ -0,0 +1,30 @@ +# +# Near Field Communication (NFC) devices +# + +menuconfig NFC_DEVICES + bool "NFC devices" + default n + ---help--- + You'll have to say Y if your computer contains an NFC device that + you want to use under Linux. + + You can say N here if you don't have any Near Field Communication + devices connected to your computer. + +if NFC_DEVICES + +config PN544_NFC + tristate "PN544 NFC driver" + depends on I2C + select CRC_CCITT + default n + ---help--- + Say yes if you want PN544 Near Field Communication driver. + This is for i2c connected version. If unsure, say N here. + + To compile this driver as a module, choose m here. The module will + be called pn544. + + +endif # NFC_DEVICES diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile new file mode 100644 index 000000000000..a4efb164ec49 --- /dev/null +++ b/drivers/nfc/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for nfc devices +# + +obj-$(CONFIG_PN544_NFC) += pn544.o diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c new file mode 100644 index 000000000000..401c44b6eadb --- /dev/null +++ b/drivers/nfc/pn544.c @@ -0,0 +1,891 @@ +/* + * Driver for the PN544 NFC chip. + * + * Copyright (C) Nokia Corporation + * + * Author: Jari Vanhala <ext-jari.vanhala@nokia.com> + * Contact: Matti Aaltonen <matti.j.aaltonen@nokia.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/completion.h> +#include <linux/crc-ccitt.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/nfc/pn544.h> +#include <linux/poll.h> +#include <linux/regulator/consumer.h> +#include <linux/serial_core.h> /* for TCGETS */ +#include <linux/slab.h> + +#define DRIVER_CARD "PN544 NFC" +#define DRIVER_DESC "NFC driver for PN544" + +static struct i2c_device_id pn544_id_table[] = { + { PN544_DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pn544_id_table); + +#define HCI_MODE 0 +#define FW_MODE 1 + +enum pn544_state { + PN544_ST_COLD, + PN544_ST_FW_READY, + PN544_ST_READY, +}; + +enum pn544_irq { + PN544_NONE, + PN544_INT, +}; + +struct pn544_info { + struct miscdevice miscdev; + struct i2c_client *i2c_dev; + struct regulator_bulk_data regs[2]; + + enum pn544_state state; + wait_queue_head_t read_wait; + loff_t read_offset; + enum pn544_irq read_irq; + struct mutex read_mutex; /* Serialize read_irq access */ + struct mutex mutex; /* Serialize info struct access */ + u8 *buf; + unsigned int buflen; +}; + +static const char reg_vdd_io[] = "Vdd_IO"; +static const char reg_vbat[] = "VBat"; + +/* sysfs interface */ +static ssize_t pn544_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pn544_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->i2c_dev; + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test()); +} + +static int pn544_enable(struct pn544_info *info, int mode) +{ + struct pn544_nfc_platform_data *pdata; + struct i2c_client *client = info->i2c_dev; + + int r; + + r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs); + if (r < 0) + return r; + + pdata = client->dev.platform_data; + info->read_irq = PN544_NONE; + if (pdata->enable) + pdata->enable(mode); + + if (mode) { + info->state = PN544_ST_FW_READY; + dev_dbg(&client->dev, "now in FW-mode\n"); + } else { + info->state = PN544_ST_READY; + dev_dbg(&client->dev, "now in HCI-mode\n"); + } + + usleep_range(10000, 15000); + + return 0; +} + +static void pn544_disable(struct pn544_info *info) +{ + struct pn544_nfc_platform_data *pdata; + struct i2c_client *client = info->i2c_dev; + + pdata = client->dev.platform_data; + if (pdata->disable) + pdata->disable(); + + info->state = PN544_ST_COLD; + + dev_dbg(&client->dev, "Now in OFF-mode\n"); + + msleep(PN544_RESETVEN_TIME); + + info->read_irq = PN544_NONE; + regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs); +} + +static int check_crc(u8 *buf, int buflen) +{ + u8 len; + u16 crc; + + len = buf[0] + 1; + if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) { + pr_err(PN544_DRIVER_NAME + ": CRC; corrupt packet len %u (%d)\n", len, buflen); + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + crc = crc_ccitt(0xffff, buf, len - 2); + crc = ~crc; + + if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) { + pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", + crc, buf[len-1], buf[len-2]); + + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + return 0; +} + +static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + if (len < 4 || len != (buf[0] + 1)) { + dev_err(&client->dev, "%s: Illegal message length: %d\n", + __func__, len); + return -EINVAL; + } + + if (check_crc(buf, len)) + return -EINVAL; + + usleep_range(3000, 6000); + + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "send: %d\n", r); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "send2: %d\n", r); + } + + if (r != len) + return -EREMOTEIO; + + return r; +} + +static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen) +{ + int r; + u8 len; + + /* + * You could read a packet in one go, but then you'd need to read + * max size and rest would be 0xff fill, so we do split reads. + */ + r = i2c_master_recv(client, &len, 1); + dev_dbg(&client->dev, "recv1: %d\n", r); + + if (r != 1) + return -EREMOTEIO; + + if (len < PN544_LLC_HCI_OVERHEAD) + len = PN544_LLC_HCI_OVERHEAD; + else if (len > (PN544_MSG_MAX_SIZE - 1)) + len = PN544_MSG_MAX_SIZE - 1; + + if (1 + len > buflen) /* len+(data+crc16) */ + return -EMSGSIZE; + + buf[0] = len; + + r = i2c_master_recv(client, buf + 1, len); + dev_dbg(&client->dev, "recv2: %d\n", r); + + if (r != len) + return -EREMOTEIO; + + usleep_range(3000, 6000); + + return r + 1; +} + +static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + dev_dbg(&client->dev, "%s\n", __func__); + + if (len < PN544_FW_HEADER_SIZE || + (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len) + return -EINVAL; + + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "fw send: %d\n", r); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + dev_dbg(&client->dev, "fw send2: %d\n", r); + } + + if (r != len) + return -EREMOTEIO; + + return r; +} + +static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen) +{ + int r, len; + + if (buflen < PN544_FW_HEADER_SIZE) + return -EINVAL; + + r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE); + dev_dbg(&client->dev, "FW recv1: %d\n", r); + + if (r < 0) + return r; + + if (r < PN544_FW_HEADER_SIZE) + return -EINVAL; + + len = (buf[1] << 8) + buf[2]; + if (len == 0) /* just header, no additional data */ + return r; + + if (len > buflen - PN544_FW_HEADER_SIZE) + return -EMSGSIZE; + + r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len); + dev_dbg(&client->dev, "fw recv2: %d\n", r); + + if (r != len) + return -EINVAL; + + return r + PN544_FW_HEADER_SIZE; +} + +static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id) +{ + struct pn544_info *info = dev_id; + struct i2c_client *client = info->i2c_dev; + + BUG_ON(!info); + BUG_ON(irq != info->i2c_dev->irq); + + dev_dbg(&client->dev, "IRQ\n"); + + mutex_lock(&info->read_mutex); + info->read_irq = PN544_INT; + mutex_unlock(&info->read_mutex); + + wake_up_interruptible(&info->read_wait); + + return IRQ_HANDLED; +} + +static enum pn544_irq pn544_irq_state(struct pn544_info *info) +{ + enum pn544_irq irq; + + mutex_lock(&info->read_mutex); + irq = info->read_irq; + mutex_unlock(&info->read_mutex); + /* + * XXX: should we check GPIO-line status directly? + * return pdata->irq_status() ? PN544_INT : PN544_NONE; + */ + + return irq; +} + +static ssize_t pn544_read(struct file *file, char __user *buf, + size_t count, loff_t *offset) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + enum pn544_irq irq; + size_t len; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, count: %zu\n", __func__, + info, count); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + irq = pn544_irq_state(info); + if (irq == PN544_NONE) { + if (file->f_flags & O_NONBLOCK) { + r = -EAGAIN; + goto out; + } + + if (wait_event_interruptible(info->read_wait, + (info->read_irq == PN544_INT))) { + r = -ERESTARTSYS; + goto out; + } + } + + if (info->state == PN544_ST_FW_READY) { + len = min(count, info->buflen); + + mutex_lock(&info->read_mutex); + r = pn544_fw_read(info->i2c_dev, info->buf, len); + info->read_irq = PN544_NONE; + mutex_unlock(&info->read_mutex); + + if (r < 0) { + dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r); + goto out; + } + + print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, r, false); + + *offset += r; + if (copy_to_user(buf, info->buf, r)) { + r = -EFAULT; + goto out; + } + } else { + len = min(count, info->buflen); + + mutex_lock(&info->read_mutex); + r = pn544_i2c_read(info->i2c_dev, info->buf, len); + info->read_irq = PN544_NONE; + mutex_unlock(&info->read_mutex); + + if (r < 0) { + dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r); + goto out; + } + print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, r, false); + + *offset += r; + if (copy_to_user(buf, info->buf, r)) { + r = -EFAULT; + goto out; + } + } + +out: + mutex_unlock(&info->mutex); + + return r; +} + +static unsigned int pn544_poll(struct file *file, poll_table *wait) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p\n", __func__, info); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + poll_wait(file, &info->read_wait, wait); + + if (pn544_irq_state(info) == PN544_INT) { + r = POLLIN | POLLRDNORM; + goto out; + } +out: + mutex_unlock(&info->mutex); + + return r; +} + +static ssize_t pn544_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + ssize_t len; + int r; + + dev_dbg(&client->dev, "%s: info: %p, count %zu\n", __func__, + info, count); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + /* + * XXX: should we detect rset-writes and clean possible + * read_irq state + */ + if (info->state == PN544_ST_FW_READY) { + size_t fw_len; + + if (count < PN544_FW_HEADER_SIZE) { + r = -EINVAL; + goto out; + } + + len = min(count, info->buflen); + if (copy_from_user(info->buf, buf, len)) { + r = -EFAULT; + goto out; + } + + print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, len, false); + + fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) + + info->buf[2]; + + if (len > fw_len) /* 1 msg at a time */ + len = fw_len; + + r = pn544_fw_write(info->i2c_dev, info->buf, len); + } else { + if (count < PN544_LLC_MIN_SIZE) { + r = -EINVAL; + goto out; + } + + len = min(count, info->buflen); + if (copy_from_user(info->buf, buf, len)) { + r = -EFAULT; + goto out; + } + + print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE, + 16, 2, info->buf, len, false); + + if (len > (info->buf[0] + 1)) /* 1 msg at a time */ + len = info->buf[0] + 1; + + r = pn544_i2c_write(info->i2c_dev, info->buf, len); + } +out: + mutex_unlock(&info->mutex); + + return r; + +} + +static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + struct pn544_nfc_platform_data *pdata; + unsigned int val; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd); + + mutex_lock(&info->mutex); + + if (info->state == PN544_ST_COLD) { + r = -ENODEV; + goto out; + } + + pdata = info->i2c_dev->dev.platform_data; + switch (cmd) { + case PN544_GET_FW_MODE: + dev_dbg(&client->dev, "%s: PN544_GET_FW_MODE\n", __func__); + + val = (info->state == PN544_ST_FW_READY); + if (copy_to_user((void __user *)arg, &val, sizeof(val))) { + r = -EFAULT; + goto out; + } + + break; + + case PN544_SET_FW_MODE: + dev_dbg(&client->dev, "%s: PN544_SET_FW_MODE\n", __func__); + + if (copy_from_user(&val, (void __user *)arg, sizeof(val))) { + r = -EFAULT; + goto out; + } + + if (val) { + if (info->state == PN544_ST_FW_READY) + break; + + pn544_disable(info); + r = pn544_enable(info, FW_MODE); + if (r < 0) + goto out; + } else { + if (info->state == PN544_ST_READY) + break; + pn544_disable(info); + r = pn544_enable(info, HCI_MODE); + if (r < 0) + goto out; + } + file->f_pos = info->read_offset; + break; + + case TCGETS: + dev_dbg(&client->dev, "%s: TCGETS\n", __func__); + + r = -ENOIOCTLCMD; + break; + + default: + dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd); + r = -ENOIOCTLCMD; + break; + } + +out: + mutex_unlock(&info->mutex); + + return r; +} + +static int pn544_open(struct inode *inode, struct file *file) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, + info, info->i2c_dev); + + mutex_lock(&info->mutex); + + /* + * Only 1 at a time. + * XXX: maybe user (counter) would work better + */ + if (info->state != PN544_ST_COLD) { + r = -EBUSY; + goto out; + } + + file->f_pos = info->read_offset; + r = pn544_enable(info, HCI_MODE); + +out: + mutex_unlock(&info->mutex); + return r; +} + +static int pn544_close(struct inode *inode, struct file *file) +{ + struct pn544_info *info = container_of(file->private_data, + struct pn544_info, miscdev); + struct i2c_client *client = info->i2c_dev; + + dev_dbg(&client->dev, "%s: info: %p, client %p\n", + __func__, info, info->i2c_dev); + + mutex_lock(&info->mutex); + pn544_disable(info); + mutex_unlock(&info->mutex); + + return 0; +} + +static const struct file_operations pn544_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = pn544_read, + .write = pn544_write, + .poll = pn544_poll, + .open = pn544_open, + .release = pn544_close, + .unlocked_ioctl = pn544_ioctl, +}; + +#ifdef CONFIG_PM +static int pn544_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pn544_info *info; + int r = 0; + + dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client); + + info = i2c_get_clientdata(client); + dev_info(&client->dev, "%s: info: %p, client %p\n", __func__, + info, client); + + mutex_lock(&info->mutex); + + switch (info->state) { + case PN544_ST_FW_READY: + /* Do not suspend while upgrading FW, please! */ + r = -EPERM; + break; + + case PN544_ST_READY: + /* + * CHECK: Device should be in standby-mode. No way to check? + * Allowing low power mode for the regulator is potentially + * dangerous if pn544 does not go to suspension. + */ + break; + + case PN544_ST_COLD: + break; + }; + + mutex_unlock(&info->mutex); + return r; +} + +static int pn544_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pn544_info *info = i2c_get_clientdata(client); + int r = 0; + + dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__, + info, client); + + mutex_lock(&info->mutex); + + switch (info->state) { + case PN544_ST_READY: + /* + * CHECK: If regulator low power mode is allowed in + * pn544_suspend, we should go back to normal mode + * here. + */ + break; + + case PN544_ST_COLD: + break; + + case PN544_ST_FW_READY: + break; + }; + + mutex_unlock(&info->mutex); + + return r; +} + +static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume); +#endif + +static struct device_attribute pn544_attr = + __ATTR(nfc_test, S_IRUGO, pn544_test, NULL); + +static int __devinit pn544_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn544_info *info; + struct pn544_nfc_platform_data *pdata; + int r = 0; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + /* private data allocation */ + info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_info.\n"); + r = -ENOMEM; + goto err_info_alloc; + } + + info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER); + info->buf = kzalloc(info->buflen, GFP_KERNEL); + if (!info->buf) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_info->buf.\n"); + r = -ENOMEM; + goto err_buf_alloc; + } + + info->regs[0].supply = reg_vdd_io; + info->regs[1].supply = reg_vbat; + r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs), + info->regs); + if (r < 0) + goto err_kmalloc; + + info->i2c_dev = client; + info->state = PN544_ST_COLD; + info->read_irq = PN544_NONE; + mutex_init(&info->read_mutex); + mutex_init(&info->mutex); + init_waitqueue_head(&info->read_wait); + i2c_set_clientdata(client, info); + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto err_reg; + } + + if (!pdata->request_resources) { + dev_err(&client->dev, "request_resources() missing\n"); + r = -EINVAL; + goto err_reg; + } + + r = pdata->request_resources(client); + if (r) { + dev_err(&client->dev, "Cannot get platform resources\n"); + goto err_reg; + } + + r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn, + IRQF_TRIGGER_RISING, PN544_DRIVER_NAME, + info); + if (r < 0) { + dev_err(&client->dev, "Unable to register IRQ handler\n"); + goto err_res; + } + + /* If we don't have the test we don't need the sysfs file */ + if (pdata->test) { + r = device_create_file(&client->dev, &pn544_attr); + if (r) { + dev_err(&client->dev, + "sysfs registration failed, error %d\n", r); + goto err_irq; + } + } + + info->miscdev.minor = MISC_DYNAMIC_MINOR; + info->miscdev.name = PN544_DRIVER_NAME; + info->miscdev.fops = &pn544_fops; + info->miscdev.parent = &client->dev; + r = misc_register(&info->miscdev); + if (r < 0) { + dev_err(&client->dev, "Device registration failed\n"); + goto err_sysfs; + } + + dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n", + __func__, info, pdata, client); + + return 0; + +err_sysfs: + if (pdata->test) + device_remove_file(&client->dev, &pn544_attr); +err_irq: + free_irq(client->irq, info); +err_res: + if (pdata->free_resources) + pdata->free_resources(); +err_reg: + regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); +err_kmalloc: + kfree(info->buf); +err_buf_alloc: + kfree(info); +err_info_alloc: + return r; +} + +static __devexit int pn544_remove(struct i2c_client *client) +{ + struct pn544_info *info = i2c_get_clientdata(client); + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + dev_dbg(&client->dev, "%s\n", __func__); + + misc_deregister(&info->miscdev); + if (pdata->test) + device_remove_file(&client->dev, &pn544_attr); + + if (info->state != PN544_ST_COLD) { + if (pdata->disable) + pdata->disable(); + + info->read_irq = PN544_NONE; + } + + free_irq(client->irq, info); + if (pdata->free_resources) + pdata->free_resources(); + + regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs); + kfree(info->buf); + kfree(info); + + return 0; +} + +static struct i2c_driver pn544_driver = { + .driver = { + .name = PN544_DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &pn544_pm_ops, +#endif + }, + .probe = pn544_probe, + .id_table = pn544_id_table, + .remove = __devexit_p(pn544_remove), +}; + +static int __init pn544_init(void) +{ + int r; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + + r = i2c_add_driver(&pn544_driver); + if (r) { + pr_err(PN544_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; +} + +static void __exit pn544_exit(void) +{ + i2c_del_driver(&pn544_driver); + pr_info(DRIVER_DESC ", Exiting.\n"); +} + +module_init(pn544_init); +module_exit(pn544_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/pcmcia/m32r_cfc.h b/drivers/pcmcia/m32r_cfc.h index 8146e3bee2e8..f558e1adf954 100644 --- a/drivers/pcmcia/m32r_cfc.h +++ b/drivers/pcmcia/m32r_cfc.h @@ -9,7 +9,7 @@ #endif /* - * M32R PC Card Controler + * M32R PC Card Controller */ #define M32R_PCC0_BASE 0x00ef7000 #define M32R_PCC1_BASE 0x00ef7020 diff --git a/drivers/pcmcia/m32r_pcc.h b/drivers/pcmcia/m32r_pcc.h index e4fffe417ba9..f95c58563bc8 100644 --- a/drivers/pcmcia/m32r_pcc.h +++ b/drivers/pcmcia/m32r_pcc.h @@ -5,7 +5,7 @@ #define M32R_MAX_PCC 2 /* - * M32R PC Card Controler + * M32R PC Card Controller */ #define M32R_PCC0_BASE 0x00ef7000 #define M32R_PCC1_BASE 0x00ef7020 diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 99d4f23cb435..0db482771fb5 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1198,7 +1198,7 @@ static int __init m8xx_probe(struct platform_device *ofdev, out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16)); - /* intialize the fixed memory windows */ + /* initialize the fixed memory windows */ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) { for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) { diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index ee40d681edd0..c5c4b8c32eb8 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1021,7 +1021,7 @@ static int update_bl_status(struct backlight_device *bd) return 0; } -static struct backlight_ops acer_bl_ops = { +static const struct backlight_ops acer_bl_ops = { .get_brightness = read_brightness, .update_status = update_bl_status, }; diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index d235f44fd7a3..f3aa6a7fdab6 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -640,7 +640,7 @@ static int update_bl_status(struct backlight_device *bd) return asus_lcd_set(asus, value); } -static struct backlight_ops asusbl_ops = { +static const struct backlight_ops asusbl_ops = { .get_brightness = asus_read_brightness, .update_status = update_bl_status, }; diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index ca05aefd03bf..4633fd8532cc 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -1467,7 +1467,7 @@ static int asus_hotk_remove(struct acpi_device *device, int type) return 0; } -static struct backlight_ops asus_backlight_data = { +static const struct backlight_ops asus_backlight_data = { .get_brightness = read_brightness, .update_status = set_brightness_status, }; diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index cf8a89a0d8f5..34657f96b5a5 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -546,7 +546,7 @@ out: return buffer->output[1]; } -static struct backlight_ops dell_ops = { +static const struct backlight_ops dell_ops = { .get_brightness = dell_get_intensity, .update_status = dell_send_intensity, }; diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index e9fc530e7dc2..49d9ad708f89 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1126,7 +1126,7 @@ static int update_bl_status(struct backlight_device *bd) return set_brightness(bd, bd->props.brightness); } -static struct backlight_ops eeepcbl_ops = { +static const struct backlight_ops eeepcbl_ops = { .get_brightness = read_brightness, .update_status = update_bl_status, }; diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index ad88b2ec34a1..19e92b2a7f7e 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -437,7 +437,7 @@ static int bl_update_status(struct backlight_device *b) return ret; } -static struct backlight_ops fujitsubl_ops = { +static const struct backlight_ops fujitsubl_ops = { .get_brightness = bl_get_brightness, .update_status = bl_update_status, }; diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index b4a95bb2f232..5e83370b0812 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -858,7 +858,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) } static struct backlight_device *sony_backlight_device; -static struct backlight_ops sony_backlight_ops = { +static const struct backlight_ops sony_backlight_ops = { .update_status = sony_backlight_update_status, .get_brightness = sony_backlight_get_brightness, }; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a974ca383cb9..dd599585c6a9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6110,7 +6110,7 @@ static void tpacpi_brightness_notify_change(void) BACKLIGHT_UPDATE_HOTKEY); } -static struct backlight_ops ibm_backlight_data = { +static const struct backlight_ops ibm_backlight_data = { .get_brightness = brightness_get, .update_status = brightness_update_status, }; @@ -7194,7 +7194,7 @@ static struct ibm_struct volume_driver_data = { * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41) * * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at - * boot. Apparently the EC does not intialize it, so unless ACPI DSDT + * boot. Apparently the EC does not initialize it, so unless ACPI DSDT * does so, its initial value is meaningless (0x07). * * For firmware bugs, refer to: diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 4276da7291b8..209cced786c6 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -841,7 +841,7 @@ static void remove_toshiba_proc_entries(void) remove_proc_entry("version", toshiba_proc_dir); } -static struct backlight_ops toshiba_backlight_data = { +static const struct backlight_ops toshiba_backlight_data = { .get_brightness = get_lcd, .update_status = set_lcd_status, }; diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index fe16b482e912..4a8ae3935b3b 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c @@ -1,5 +1,5 @@ /* - * iPAQ h1930/h1940/rx1950 battery controler driver + * iPAQ h1930/h1940/rx1950 battery controller driver * Copyright (c) Vasily Khoruzhick * Based on h1940_battery.c by Arnaud Patard * @@ -427,5 +427,5 @@ static void __exit s3c_adc_bat_exit(void) module_exit(s3c_adc_bat_exit); MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>"); -MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controler driver"); +MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig index 1afe4e03440f..f0d3376b58ba 100644 --- a/drivers/pps/Kconfig +++ b/drivers/pps/Kconfig @@ -30,6 +30,17 @@ config PPS_DEBUG messages to the system log. Select this if you are having a problem with PPS support and want to see more of what is going on. +config NTP_PPS + bool "PPS kernel consumer support" + depends on PPS && !NO_HZ + help + This option adds support for direct in-kernel time + syncronization using an external PPS signal. + + It doesn't work on tickless systems at the moment. + source drivers/pps/clients/Kconfig +source drivers/pps/generators/Kconfig + endmenu diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile index 98960ddd3188..4483eaadaddd 100644 --- a/drivers/pps/Makefile +++ b/drivers/pps/Makefile @@ -3,7 +3,8 @@ # pps_core-y := pps.o kapi.o sysfs.o +pps_core-$(CONFIG_NTP_PPS) += kc.o obj-$(CONFIG_PPS) := pps_core.o -obj-y += clients/ +obj-y += clients/ generators/ ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig index 4e801bd7254f..8520a7f4dd62 100644 --- a/drivers/pps/clients/Kconfig +++ b/drivers/pps/clients/Kconfig @@ -22,4 +22,11 @@ config PPS_CLIENT_LDISC If you say yes here you get support for a PPS source connected with the CD (Carrier Detect) pin of your serial port. +config PPS_CLIENT_PARPORT + tristate "Parallel port PPS client" + depends on PPS && PARPORT + help + If you say yes here you get support for a PPS source connected + with the interrupt pin of your parallel port. + endif diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile index 812c9b19b430..42517da07049 100644 --- a/drivers/pps/clients/Makefile +++ b/drivers/pps/clients/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o +obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o ifeq ($(CONFIG_PPS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c index e7ef5b8186d0..2728469d3884 100644 --- a/drivers/pps/clients/pps-ktimer.c +++ b/drivers/pps/clients/pps-ktimer.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/module.h> @@ -31,7 +32,7 @@ * Global variables */ -static int source; +static struct pps_device *pps; static struct timer_list ktimer; /* @@ -40,19 +41,14 @@ static struct timer_list ktimer; static void pps_ktimer_event(unsigned long ptr) { - struct timespec __ts; - struct pps_ktime ts; + struct pps_event_time ts; /* First of all we get the time stamp... */ - getnstimeofday(&__ts); + pps_get_ts(&ts); - pr_info("PPS event at %lu\n", jiffies); + dev_info(pps->dev, "PPS event at %lu\n", jiffies); - /* ... and translate it to PPS time data struct */ - ts.sec = __ts.tv_sec; - ts.nsec = __ts.tv_nsec; - - pps_event(source, &ts, PPS_CAPTUREASSERT, NULL); + pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); } @@ -61,12 +57,11 @@ static void pps_ktimer_event(unsigned long ptr) * The echo function */ -static void pps_ktimer_echo(int source, int event, void *data) +static void pps_ktimer_echo(struct pps_device *pps, int event, void *data) { - pr_info("echo %s %s for source %d\n", + dev_info(pps->dev, "echo %s %s\n", event & PPS_CAPTUREASSERT ? "assert" : "", - event & PPS_CAPTURECLEAR ? "clear" : "", - source); + event & PPS_CAPTURECLEAR ? "clear" : ""); } /* @@ -89,30 +84,27 @@ static struct pps_source_info pps_ktimer_info = { static void __exit pps_ktimer_exit(void) { - del_timer_sync(&ktimer); - pps_unregister_source(source); + dev_info(pps->dev, "ktimer PPS source unregistered\n"); - pr_info("ktimer PPS source unregistered\n"); + del_timer_sync(&ktimer); + pps_unregister_source(pps); } static int __init pps_ktimer_init(void) { - int ret; - - ret = pps_register_source(&pps_ktimer_info, + pps = pps_register_source(&pps_ktimer_info, PPS_CAPTUREASSERT | PPS_OFFSETASSERT); - if (ret < 0) { - printk(KERN_ERR "cannot register ktimer source\n"); - return ret; + if (pps == NULL) { + pr_err("cannot register PPS source\n"); + return -ENOMEM; } - source = ret; setup_timer(&ktimer, pps_ktimer_event, 0); mod_timer(&ktimer, jiffies + HZ); - pr_info("ktimer PPS source registered at %d\n", source); + dev_info(pps->dev, "ktimer PPS source registered\n"); - return 0; + return 0; } module_init(pps_ktimer_init); diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c index 8e1932d29fd4..79451f2dea6a 100644 --- a/drivers/pps/clients/pps-ldisc.c +++ b/drivers/pps/clients/pps-ldisc.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/serial_core.h> #include <linux/tty.h> @@ -27,30 +29,18 @@ #define PPS_TTY_MAGIC 0x0001 static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, - struct timespec *ts) + struct pps_event_time *ts) { - int id = (long)tty->disc_data; - struct timespec __ts; - struct pps_ktime pps_ts; - - /* First of all we get the time stamp... */ - getnstimeofday(&__ts); - - /* Does caller give us a timestamp? */ - if (ts) { /* Yes. Let's use it! */ - pps_ts.sec = ts->tv_sec; - pps_ts.nsec = ts->tv_nsec; - } else { /* No. Do it ourself! */ - pps_ts.sec = __ts.tv_sec; - pps_ts.nsec = __ts.tv_nsec; - } + struct pps_device *pps = (struct pps_device *)tty->disc_data; + + BUG_ON(pps == NULL); /* Now do the PPS event report */ - pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR, - NULL); + pps_event(pps, ts, status ? PPS_CAPTUREASSERT : + PPS_CAPTURECLEAR, NULL); - pr_debug("PPS %s at %lu on source #%d\n", - status ? "assert" : "clear", jiffies, id); + dev_dbg(pps->dev, "PPS %s at %lu\n", + status ? "assert" : "clear", jiffies); } static int (*alias_n_tty_open)(struct tty_struct *tty); @@ -60,6 +50,7 @@ static int pps_tty_open(struct tty_struct *tty) struct pps_source_info info; struct tty_driver *drv = tty->driver; int index = tty->index + drv->name_base; + struct pps_device *pps; int ret; info.owner = THIS_MODULE; @@ -70,34 +61,42 @@ static int pps_tty_open(struct tty_struct *tty) PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ PPS_CANWAIT | PPS_TSFMT_TSPEC; - ret = pps_register_source(&info, PPS_CAPTUREBOTH | \ + pps = pps_register_source(&info, PPS_CAPTUREBOTH | \ PPS_OFFSETASSERT | PPS_OFFSETCLEAR); - if (ret < 0) { + if (pps == NULL) { pr_err("cannot register PPS source \"%s\"\n", info.path); - return ret; + return -ENOMEM; } - tty->disc_data = (void *)(long)ret; + tty->disc_data = pps; /* Should open N_TTY ldisc too */ ret = alias_n_tty_open(tty); - if (ret < 0) - pps_unregister_source((long)tty->disc_data); + if (ret < 0) { + pr_err("cannot open tty ldisc \"%s\"\n", info.path); + goto err_unregister; + } - pr_info("PPS source #%d \"%s\" added\n", ret, info.path); + dev_info(pps->dev, "source \"%s\" added\n", info.path); return 0; + +err_unregister: + tty->disc_data = NULL; + pps_unregister_source(pps); + return ret; } static void (*alias_n_tty_close)(struct tty_struct *tty); static void pps_tty_close(struct tty_struct *tty) { - int id = (long)tty->disc_data; + struct pps_device *pps = (struct pps_device *)tty->disc_data; - pps_unregister_source(id); alias_n_tty_close(tty); - pr_info("PPS source #%d removed\n", id); + tty->disc_data = NULL; + dev_info(pps->dev, "removed\n"); + pps_unregister_source(pps); } static struct tty_ldisc_ops pps_ldisc_ops; diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c new file mode 100644 index 000000000000..32221efd9ca9 --- /dev/null +++ b/drivers/pps/clients/pps_parport.c @@ -0,0 +1,258 @@ +/* + * pps_parport.c -- kernel parallel port PPS client + * + * + * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su> + * + * 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. + */ + + +/* + * TODO: + * implement echo over SEL pin + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/irqnr.h> +#include <linux/time.h> +#include <linux/parport.h> +#include <linux/pps_kernel.h> + +#define DRVDESC "parallel port PPS client" + +/* module parameters */ + +#define CLEAR_WAIT_MAX 100 +#define CLEAR_WAIT_MAX_ERRORS 5 + +static unsigned int clear_wait = 100; +MODULE_PARM_DESC(clear_wait, + "Maximum number of port reads when polling for signal clear," + " zero turns clear edge capture off entirely"); +module_param(clear_wait, uint, 0); + + +/* internal per port structure */ +struct pps_client_pp { + struct pardevice *pardev; /* parport device */ + struct pps_device *pps; /* PPS device */ + unsigned int cw; /* port clear timeout */ + unsigned int cw_err; /* number of timeouts */ +}; + +static inline int signal_is_set(struct parport *port) +{ + return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0; +} + +/* parport interrupt handler */ +static void parport_irq(void *handle) +{ + struct pps_event_time ts_assert, ts_clear; + struct pps_client_pp *dev = handle; + struct parport *port = dev->pardev->port; + unsigned int i; + unsigned long flags; + + /* first of all we get the time stamp... */ + pps_get_ts(&ts_assert); + + if (dev->cw == 0) + /* clear edge capture disabled */ + goto out_assert; + + /* try capture the clear edge */ + + /* We have to disable interrupts here. The idea is to prevent + * other interrupts on the same processor to introduce random + * lags while polling the port. Reading from IO port is known + * to take approximately 1us while other interrupt handlers can + * take much more potentially. + * + * Interrupts won't be disabled for a long time because the + * number of polls is limited by clear_wait parameter which is + * kept rather low. So it should never be an issue. + */ + local_irq_save(flags); + /* check the signal (no signal means the pulse is lost this time) */ + if (!signal_is_set(port)) { + local_irq_restore(flags); + dev_err(dev->pps->dev, "lost the signal\n"); + goto out_assert; + } + + /* poll the port until the signal is unset */ + for (i = dev->cw; i; i--) + if (!signal_is_set(port)) { + pps_get_ts(&ts_clear); + local_irq_restore(flags); + dev->cw_err = 0; + goto out_both; + } + local_irq_restore(flags); + + /* timeout */ + dev->cw_err++; + if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) { + dev_err(dev->pps->dev, "disabled clear edge capture after %d" + " timeouts\n", dev->cw_err); + dev->cw = 0; + dev->cw_err = 0; + } + +out_assert: + /* fire assert event */ + pps_event(dev->pps, &ts_assert, + PPS_CAPTUREASSERT, NULL); + return; + +out_both: + /* fire assert event */ + pps_event(dev->pps, &ts_assert, + PPS_CAPTUREASSERT, NULL); + /* fire clear event */ + pps_event(dev->pps, &ts_clear, + PPS_CAPTURECLEAR, NULL); + return; +} + +/* the PPS echo function */ +static void pps_echo(struct pps_device *pps, int event, void *data) +{ + dev_info(pps->dev, "echo %s %s\n", + event & PPS_CAPTUREASSERT ? "assert" : "", + event & PPS_CAPTURECLEAR ? "clear" : ""); +} + +static void parport_attach(struct parport *port) +{ + struct pps_client_pp *device; + struct pps_source_info info = { + .name = KBUILD_MODNAME, + .path = "", + .mode = PPS_CAPTUREBOTH | \ + PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ + PPS_ECHOASSERT | PPS_ECHOCLEAR | \ + PPS_CANWAIT | PPS_TSFMT_TSPEC, + .echo = pps_echo, + .owner = THIS_MODULE, + .dev = NULL + }; + + device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL); + if (!device) { + pr_err("memory allocation failed, not attaching\n"); + return; + } + + device->pardev = parport_register_device(port, KBUILD_MODNAME, + NULL, NULL, parport_irq, 0, device); + if (!device->pardev) { + pr_err("couldn't register with %s\n", port->name); + goto err_free; + } + + if (parport_claim_or_block(device->pardev) < 0) { + pr_err("couldn't claim %s\n", port->name); + goto err_unregister_dev; + } + + device->pps = pps_register_source(&info, + PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR); + if (device->pps == NULL) { + pr_err("couldn't register PPS source\n"); + goto err_release_dev; + } + + device->cw = clear_wait; + + port->ops->enable_irq(port); + + pr_info("attached to %s\n", port->name); + + return; + +err_release_dev: + parport_release(device->pardev); +err_unregister_dev: + parport_unregister_device(device->pardev); +err_free: + kfree(device); +} + +static void parport_detach(struct parport *port) +{ + struct pardevice *pardev = port->cad; + struct pps_client_pp *device; + + /* FIXME: oooh, this is ugly! */ + if (strcmp(pardev->name, KBUILD_MODNAME)) + /* not our port */ + return; + + device = pardev->private; + + port->ops->disable_irq(port); + pps_unregister_source(device->pps); + parport_release(pardev); + parport_unregister_device(pardev); + kfree(device); +} + +static struct parport_driver pps_parport_driver = { + .name = KBUILD_MODNAME, + .attach = parport_attach, + .detach = parport_detach, +}; + +/* module staff */ + +static int __init pps_parport_init(void) +{ + int ret; + + pr_info(DRVDESC "\n"); + + if (clear_wait > CLEAR_WAIT_MAX) { + pr_err("clear_wait value should be not greater" + " then %d\n", CLEAR_WAIT_MAX); + return -EINVAL; + } + + ret = parport_register_driver(&pps_parport_driver); + if (ret) { + pr_err("unable to register with parport\n"); + return ret; + } + + return 0; +} + +static void __exit pps_parport_exit(void) +{ + parport_unregister_driver(&pps_parport_driver); +} + +module_init(pps_parport_init); +module_exit(pps_parport_exit); + +MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>"); +MODULE_DESCRIPTION(DRVDESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig new file mode 100644 index 000000000000..f3a73dd77660 --- /dev/null +++ b/drivers/pps/generators/Kconfig @@ -0,0 +1,13 @@ +# +# PPS generators configuration +# + +comment "PPS generators support" + +config PPS_GENERATOR_PARPORT + tristate "Parallel port PPS signal generator" + depends on PARPORT + help + If you say yes here you get support for a PPS signal generator which + utilizes STROBE pin of a parallel port to send PPS signals. It uses + parport abstraction layer and hrtimers to precisely control the signal. diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile new file mode 100644 index 000000000000..303304a6b8ec --- /dev/null +++ b/drivers/pps/generators/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for PPS generators. +# + +obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o + +ifeq ($(CONFIG_PPS_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c new file mode 100644 index 000000000000..5c32f8dacf56 --- /dev/null +++ b/drivers/pps/generators/pps_gen_parport.c @@ -0,0 +1,282 @@ +/* + * pps_gen_parport.c -- kernel parallel port PPS signal generator + * + * + * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su> + * + * 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. + */ + + +/* + * TODO: + * fix issues when realtime clock is adjusted in a leap + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/hrtimer.h> +#include <linux/parport.h> + +#define DRVDESC "parallel port PPS signal generator" + +#define SIGNAL 0 +#define NO_SIGNAL PARPORT_CONTROL_STROBE + +/* module parameters */ + +#define SEND_DELAY_MAX 100000 + +static unsigned int send_delay = 30000; +MODULE_PARM_DESC(delay, + "Delay between setting and dropping the signal (ns)"); +module_param_named(delay, send_delay, uint, 0); + + +#define SAFETY_INTERVAL 3000 /* set the hrtimer earlier for safety (ns) */ + +/* internal per port structure */ +struct pps_generator_pp { + struct pardevice *pardev; /* parport device */ + struct hrtimer timer; + long port_write_time; /* calibrated port write time (ns) */ +}; + +static struct pps_generator_pp device = { + .pardev = NULL, +}; + +static int attached; + +/* calibrated time between a hrtimer event and the reaction */ +static long hrtimer_error = SAFETY_INTERVAL; + +/* the kernel hrtimer event */ +static enum hrtimer_restart hrtimer_event(struct hrtimer *timer) +{ + struct timespec expire_time, ts1, ts2, ts3, dts; + struct pps_generator_pp *dev; + struct parport *port; + long lim, delta; + unsigned long flags; + + /* We have to disable interrupts here. The idea is to prevent + * other interrupts on the same processor to introduce random + * lags while polling the clock. getnstimeofday() takes <1us on + * most machines while other interrupt handlers can take much + * more potentially. + * + * NB: approx time with blocked interrupts = + * send_delay + 3 * SAFETY_INTERVAL + */ + local_irq_save(flags); + + /* first of all we get the time stamp... */ + getnstimeofday(&ts1); + expire_time = ktime_to_timespec(hrtimer_get_softexpires(timer)); + dev = container_of(timer, struct pps_generator_pp, timer); + lim = NSEC_PER_SEC - send_delay - dev->port_write_time; + + /* check if we are late */ + if (expire_time.tv_sec != ts1.tv_sec || ts1.tv_nsec > lim) { + local_irq_restore(flags); + pr_err("we are late this time %ld.%09ld\n", + ts1.tv_sec, ts1.tv_nsec); + goto done; + } + + /* busy loop until the time is right for an assert edge */ + do { + getnstimeofday(&ts2); + } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim); + + /* set the signal */ + port = dev->pardev->port; + port->ops->write_control(port, SIGNAL); + + /* busy loop until the time is right for a clear edge */ + lim = NSEC_PER_SEC - dev->port_write_time; + do { + getnstimeofday(&ts2); + } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim); + + /* unset the signal */ + port->ops->write_control(port, NO_SIGNAL); + + getnstimeofday(&ts3); + + local_irq_restore(flags); + + /* update calibrated port write time */ + dts = timespec_sub(ts3, ts2); + dev->port_write_time = + (dev->port_write_time + timespec_to_ns(&dts)) >> 1; + +done: + /* update calibrated hrtimer error */ + dts = timespec_sub(ts1, expire_time); + delta = timespec_to_ns(&dts); + /* If the new error value is bigger then the old, use the new + * value, if not then slowly move towards the new value. This + * way it should be safe in bad conditions and efficient in + * good conditions. + */ + if (delta >= hrtimer_error) + hrtimer_error = delta; + else + hrtimer_error = (3 * hrtimer_error + delta) >> 2; + + /* update the hrtimer expire time */ + hrtimer_set_expires(timer, + ktime_set(expire_time.tv_sec + 1, + NSEC_PER_SEC - (send_delay + + dev->port_write_time + SAFETY_INTERVAL + + 2 * hrtimer_error))); + + return HRTIMER_RESTART; +} + +/* calibrate port write time */ +#define PORT_NTESTS_SHIFT 5 +static void calibrate_port(struct pps_generator_pp *dev) +{ + struct parport *port = dev->pardev->port; + int i; + long acc = 0; + + for (i = 0; i < (1 << PORT_NTESTS_SHIFT); i++) { + struct timespec a, b; + unsigned long irq_flags; + + local_irq_save(irq_flags); + getnstimeofday(&a); + port->ops->write_control(port, NO_SIGNAL); + getnstimeofday(&b); + local_irq_restore(irq_flags); + + b = timespec_sub(b, a); + acc += timespec_to_ns(&b); + } + + dev->port_write_time = acc >> PORT_NTESTS_SHIFT; + pr_info("port write takes %ldns\n", dev->port_write_time); +} + +static inline ktime_t next_intr_time(struct pps_generator_pp *dev) +{ + struct timespec ts; + + getnstimeofday(&ts); + + return ktime_set(ts.tv_sec + + ((ts.tv_nsec > 990 * NSEC_PER_MSEC) ? 1 : 0), + NSEC_PER_SEC - (send_delay + + dev->port_write_time + 3 * SAFETY_INTERVAL)); +} + +static void parport_attach(struct parport *port) +{ + if (attached) { + /* we already have a port */ + return; + } + + device.pardev = parport_register_device(port, KBUILD_MODNAME, + NULL, NULL, NULL, 0, &device); + if (!device.pardev) { + pr_err("couldn't register with %s\n", port->name); + return; + } + + if (parport_claim_or_block(device.pardev) < 0) { + pr_err("couldn't claim %s\n", port->name); + goto err_unregister_dev; + } + + pr_info("attached to %s\n", port->name); + attached = 1; + + calibrate_port(&device); + + hrtimer_init(&device.timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); + device.timer.function = hrtimer_event; +#ifdef CONFIG_PREEMPT_RT + /* hrtimer interrupt will run in the interrupt context with this */ + device.timer.irqsafe = 1; +#endif + + hrtimer_start(&device.timer, next_intr_time(&device), HRTIMER_MODE_ABS); + + return; + +err_unregister_dev: + parport_unregister_device(device.pardev); +} + +static void parport_detach(struct parport *port) +{ + if (port->cad != device.pardev) + return; /* not our port */ + + hrtimer_cancel(&device.timer); + parport_release(device.pardev); + parport_unregister_device(device.pardev); +} + +static struct parport_driver pps_gen_parport_driver = { + .name = KBUILD_MODNAME, + .attach = parport_attach, + .detach = parport_detach, +}; + +/* module staff */ + +static int __init pps_gen_parport_init(void) +{ + int ret; + + pr_info(DRVDESC "\n"); + + if (send_delay > SEND_DELAY_MAX) { + pr_err("delay value should be not greater" + " then %d\n", SEND_DELAY_MAX); + return -EINVAL; + } + + ret = parport_register_driver(&pps_gen_parport_driver); + if (ret) { + pr_err("unable to register with parport\n"); + return ret; + } + + return 0; +} + +static void __exit pps_gen_parport_exit(void) +{ + parport_unregister_driver(&pps_gen_parport_driver); + pr_info("hrtimer avg error is %ldns\n", hrtimer_error); +} + +module_init(pps_gen_parport_init); +module_exit(pps_gen_parport_exit); + +MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>"); +MODULE_DESCRIPTION(DRVDESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c index 1aa02db3ff4e..cba1b43f7519 100644 --- a/drivers/pps/kapi.c +++ b/drivers/pps/kapi.c @@ -19,24 +19,20 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/time.h> +#include <linux/timex.h> #include <linux/spinlock.h> -#include <linux/idr.h> #include <linux/fs.h> #include <linux/pps_kernel.h> #include <linux/slab.h> -/* - * Global variables - */ - -DEFINE_SPINLOCK(pps_idr_lock); -DEFINE_IDR(pps_idr); +#include "kc.h" /* * Local functions @@ -60,60 +56,6 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset) * Exported functions */ -/* pps_get_source - find a PPS source - * @source: the PPS source ID. - * - * This function is used to find an already registered PPS source into the - * system. - * - * The function returns NULL if found nothing, otherwise it returns a pointer - * to the PPS source data struct (the refcounter is incremented by 1). - */ - -struct pps_device *pps_get_source(int source) -{ - struct pps_device *pps; - unsigned long flags; - - spin_lock_irqsave(&pps_idr_lock, flags); - - pps = idr_find(&pps_idr, source); - if (pps != NULL) - atomic_inc(&pps->usage); - - spin_unlock_irqrestore(&pps_idr_lock, flags); - - return pps; -} - -/* pps_put_source - free the PPS source data - * @pps: a pointer to the PPS source. - * - * This function is used to free a PPS data struct if its refcount is 0. - */ - -void pps_put_source(struct pps_device *pps) -{ - unsigned long flags; - - spin_lock_irqsave(&pps_idr_lock, flags); - BUG_ON(atomic_read(&pps->usage) == 0); - - if (!atomic_dec_and_test(&pps->usage)) { - pps = NULL; - goto exit; - } - - /* No more reference to the PPS source. We can safely remove the - * PPS data struct. - */ - idr_remove(&pps_idr, pps->id); - -exit: - spin_unlock_irqrestore(&pps_idr_lock, flags); - kfree(pps); -} - /* pps_register_source - add a PPS source in the system * @info: the PPS info struct * @default_params: the default PPS parameters of the new source @@ -122,31 +64,31 @@ exit: * source is described by info's fields and it will have, as default PPS * parameters, the ones specified into default_params. * - * The function returns, in case of success, the PPS source ID. + * The function returns, in case of success, the PPS device. Otherwise NULL. */ -int pps_register_source(struct pps_source_info *info, int default_params) +struct pps_device *pps_register_source(struct pps_source_info *info, + int default_params) { struct pps_device *pps; - int id; int err; /* Sanity checks */ if ((info->mode & default_params) != default_params) { - printk(KERN_ERR "pps: %s: unsupported default parameters\n", + pr_err("%s: unsupported default parameters\n", info->name); err = -EINVAL; goto pps_register_source_exit; } if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 && info->echo == NULL) { - printk(KERN_ERR "pps: %s: echo function is not defined\n", + pr_err("%s: echo function is not defined\n", info->name); err = -EINVAL; goto pps_register_source_exit; } if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { - printk(KERN_ERR "pps: %s: unspecified time format\n", + pr_err("%s: unspecified time format\n", info->name); err = -EINVAL; goto pps_register_source_exit; @@ -168,94 +110,48 @@ int pps_register_source(struct pps_source_info *info, int default_params) init_waitqueue_head(&pps->queue); spin_lock_init(&pps->lock); - atomic_set(&pps->usage, 1); - - /* Get new ID for the new PPS source */ - if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { - err = -ENOMEM; - goto kfree_pps; - } - - spin_lock_irq(&pps_idr_lock); - - /* Now really allocate the PPS source. - * After idr_get_new() calling the new source will be freely available - * into the kernel. - */ - err = idr_get_new(&pps_idr, pps, &id); - if (err < 0) { - spin_unlock_irq(&pps_idr_lock); - goto kfree_pps; - } - - id = id & MAX_ID_MASK; - if (id >= PPS_MAX_SOURCES) { - spin_unlock_irq(&pps_idr_lock); - - printk(KERN_ERR "pps: %s: too many PPS sources in the system\n", - info->name); - err = -EBUSY; - goto free_idr; - } - pps->id = id; - - spin_unlock_irq(&pps_idr_lock); /* Create the char device */ err = pps_register_cdev(pps); if (err < 0) { - printk(KERN_ERR "pps: %s: unable to create char device\n", + pr_err("%s: unable to create char device\n", info->name); - goto free_idr; + goto kfree_pps; } - pr_info("new PPS source %s at ID %d\n", info->name, id); + dev_info(pps->dev, "new PPS source %s\n", info->name); - return id; - -free_idr: - spin_lock_irq(&pps_idr_lock); - idr_remove(&pps_idr, id); - spin_unlock_irq(&pps_idr_lock); + return pps; kfree_pps: kfree(pps); pps_register_source_exit: - printk(KERN_ERR "pps: %s: unable to register source\n", info->name); + pr_err("%s: unable to register source\n", info->name); - return err; + return NULL; } EXPORT_SYMBOL(pps_register_source); /* pps_unregister_source - remove a PPS source from the system - * @source: the PPS source ID + * @pps: the PPS source * * This function is used to remove a previously registered PPS source from * the system. */ -void pps_unregister_source(int source) +void pps_unregister_source(struct pps_device *pps) { - struct pps_device *pps; - - spin_lock_irq(&pps_idr_lock); - pps = idr_find(&pps_idr, source); - - if (!pps) { - BUG(); - spin_unlock_irq(&pps_idr_lock); - return; - } - spin_unlock_irq(&pps_idr_lock); - + pps_kc_remove(pps); pps_unregister_cdev(pps); - pps_put_source(pps); + + /* don't have to kfree(pps) here because it will be done on + * device destruction */ } EXPORT_SYMBOL(pps_unregister_source); /* pps_event - register a PPS event into the system - * @source: the PPS source ID + * @pps: the PPS device * @ts: the event timestamp * @event: the event type * @data: userdef pointer @@ -263,78 +159,72 @@ EXPORT_SYMBOL(pps_unregister_source); * This function is used by each PPS client in order to register a new * PPS event into the system (it's usually called inside an IRQ handler). * - * If an echo function is associated with the PPS source it will be called + * If an echo function is associated with the PPS device it will be called * as: - * pps->info.echo(source, event, data); + * pps->info.echo(pps, event, data); */ - -void pps_event(int source, struct pps_ktime *ts, int event, void *data) +void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event, + void *data) { - struct pps_device *pps; unsigned long flags; int captured = 0; + struct pps_ktime ts_real; - if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { - printk(KERN_ERR "pps: unknown event (%x) for source %d\n", - event, source); - return; - } + /* check event type */ + BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0); - pps = pps_get_source(source); - if (!pps) - return; + dev_dbg(pps->dev, "PPS event at %ld.%09ld\n", + ts->ts_real.tv_sec, ts->ts_real.tv_nsec); - pr_debug("PPS event on source %d at %llu.%06u\n", - pps->id, (unsigned long long) ts->sec, ts->nsec); + timespec_to_pps_ktime(&ts_real, ts->ts_real); spin_lock_irqsave(&pps->lock, flags); /* Must call the echo function? */ if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) - pps->info.echo(source, event, data); + pps->info.echo(pps, event, data); /* Check the event */ pps->current_mode = pps->params.mode; - if ((event & PPS_CAPTUREASSERT) & - (pps->params.mode & PPS_CAPTUREASSERT)) { + if (event & pps->params.mode & PPS_CAPTUREASSERT) { /* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETASSERT) - pps_add_offset(ts, &pps->params.assert_off_tu); + pps_add_offset(&ts_real, + &pps->params.assert_off_tu); /* Save the time stamp */ - pps->assert_tu = *ts; + pps->assert_tu = ts_real; pps->assert_sequence++; - pr_debug("capture assert seq #%u for source %d\n", - pps->assert_sequence, source); + dev_dbg(pps->dev, "capture assert seq #%u\n", + pps->assert_sequence); captured = ~0; } - if ((event & PPS_CAPTURECLEAR) & - (pps->params.mode & PPS_CAPTURECLEAR)) { + if (event & pps->params.mode & PPS_CAPTURECLEAR) { /* We have to add an offset? */ if (pps->params.mode & PPS_OFFSETCLEAR) - pps_add_offset(ts, &pps->params.clear_off_tu); + pps_add_offset(&ts_real, + &pps->params.clear_off_tu); /* Save the time stamp */ - pps->clear_tu = *ts; + pps->clear_tu = ts_real; pps->clear_sequence++; - pr_debug("capture clear seq #%u for source %d\n", - pps->clear_sequence, source); + dev_dbg(pps->dev, "capture clear seq #%u\n", + pps->clear_sequence); captured = ~0; } - /* Wake up iif captured somthing */ + pps_kc_event(pps, ts, event); + + /* Wake up if captured something */ if (captured) { - pps->go = ~0; - wake_up_interruptible(&pps->queue); + pps->last_ev++; + wake_up_interruptible_all(&pps->queue); kill_fasync(&pps->async_queue, SIGIO, POLL_IN); } spin_unlock_irqrestore(&pps->lock, flags); - - /* Now we can release the PPS source for (possible) deregistration */ - pps_put_source(pps); } EXPORT_SYMBOL(pps_event); diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c new file mode 100644 index 000000000000..079e930b1938 --- /dev/null +++ b/drivers/pps/kc.c @@ -0,0 +1,122 @@ +/* + * PPS kernel consumer API + * + * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su> + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/pps_kernel.h> + +#include "kc.h" + +/* + * Global variables + */ + +/* state variables to bind kernel consumer */ +DEFINE_SPINLOCK(pps_kc_hardpps_lock); +/* PPS API (RFC 2783): current source and mode for kernel consumer */ +struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */ +int pps_kc_hardpps_mode; /* mode bits for kernel consumer */ + +/* pps_kc_bind - control PPS kernel consumer binding + * @pps: the PPS source + * @bind_args: kernel consumer bind parameters + * + * This function is used to bind or unbind PPS kernel consumer according to + * supplied parameters. Should not be called in interrupt context. + */ +int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args) +{ + /* Check if another consumer is already bound */ + spin_lock_irq(&pps_kc_hardpps_lock); + + if (bind_args->edge == 0) + if (pps_kc_hardpps_dev == pps) { + pps_kc_hardpps_mode = 0; + pps_kc_hardpps_dev = NULL; + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_info(pps->dev, "unbound kernel" + " consumer\n"); + } else { + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_err(pps->dev, "selected kernel consumer" + " is not bound\n"); + return -EINVAL; + } + else + if (pps_kc_hardpps_dev == NULL || + pps_kc_hardpps_dev == pps) { + pps_kc_hardpps_mode = bind_args->edge; + pps_kc_hardpps_dev = pps; + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_info(pps->dev, "bound kernel consumer: " + "edge=0x%x\n", bind_args->edge); + } else { + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_err(pps->dev, "another kernel consumer" + " is already bound\n"); + return -EINVAL; + } + + return 0; +} + +/* pps_kc_remove - unbind kernel consumer on PPS source removal + * @pps: the PPS source + * + * This function is used to disable kernel consumer on PPS source removal + * if this source was bound to PPS kernel consumer. Can be called on any + * source safely. Should not be called in interrupt context. + */ +void pps_kc_remove(struct pps_device *pps) +{ + spin_lock_irq(&pps_kc_hardpps_lock); + if (pps == pps_kc_hardpps_dev) { + pps_kc_hardpps_mode = 0; + pps_kc_hardpps_dev = NULL; + spin_unlock_irq(&pps_kc_hardpps_lock); + dev_info(pps->dev, "unbound kernel consumer" + " on device removal\n"); + } else + spin_unlock_irq(&pps_kc_hardpps_lock); +} + +/* pps_kc_event - call hardpps() on PPS event + * @pps: the PPS source + * @ts: PPS event timestamp + * @event: PPS event edge + * + * This function calls hardpps() when an event from bound PPS source occurs. + */ +void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts, + int event) +{ + unsigned long flags; + + /* Pass some events to kernel consumer if activated */ + spin_lock_irqsave(&pps_kc_hardpps_lock, flags); + if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode) + hardpps(&ts->ts_real, &ts->ts_raw); + spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags); +} diff --git a/drivers/pps/kc.h b/drivers/pps/kc.h new file mode 100644 index 000000000000..d296fcd0a175 --- /dev/null +++ b/drivers/pps/kc.h @@ -0,0 +1,46 @@ +/* + * PPS kernel consumer API header + * + * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su> + * + * 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 LINUX_PPS_KC_H +#define LINUX_PPS_KC_H + +#include <linux/errno.h> +#include <linux/pps_kernel.h> + +#ifdef CONFIG_NTP_PPS + +extern int pps_kc_bind(struct pps_device *pps, + struct pps_bind_args *bind_args); +extern void pps_kc_remove(struct pps_device *pps); +extern void pps_kc_event(struct pps_device *pps, + struct pps_event_time *ts, int event); + + +#else /* CONFIG_NTP_PPS */ + +static inline int pps_kc_bind(struct pps_device *pps, + struct pps_bind_args *bind_args) { return -EOPNOTSUPP; } +static inline void pps_kc_remove(struct pps_device *pps) {} +static inline void pps_kc_event(struct pps_device *pps, + struct pps_event_time *ts, int event) {} + +#endif /* CONFIG_NTP_PPS */ + +#endif /* LINUX_PPS_KC_H */ diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index ca5183bdad85..2baadd21b7a6 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/module.h> @@ -26,9 +27,13 @@ #include <linux/sched.h> #include <linux/uaccess.h> #include <linux/idr.h> +#include <linux/mutex.h> #include <linux/cdev.h> #include <linux/poll.h> #include <linux/pps_kernel.h> +#include <linux/slab.h> + +#include "kc.h" /* * Local variables @@ -37,6 +42,9 @@ static dev_t pps_devt; static struct class *pps_class; +static DEFINE_MUTEX(pps_idr_lock); +static DEFINE_IDR(pps_idr); + /* * Char device methods */ @@ -61,15 +69,13 @@ static long pps_cdev_ioctl(struct file *file, { struct pps_device *pps = file->private_data; struct pps_kparams params; - struct pps_fdata fdata; - unsigned long ticks; void __user *uarg = (void __user *) arg; int __user *iuarg = (int __user *) arg; int err; switch (cmd) { case PPS_GETPARAMS: - pr_debug("PPS_GETPARAMS: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_GETPARAMS\n"); spin_lock_irq(&pps->lock); @@ -85,7 +91,7 @@ static long pps_cdev_ioctl(struct file *file, break; case PPS_SETPARAMS: - pr_debug("PPS_SETPARAMS: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_SETPARAMS\n"); /* Check the capabilities */ if (!capable(CAP_SYS_TIME)) @@ -95,14 +101,14 @@ static long pps_cdev_ioctl(struct file *file, if (err) return -EFAULT; if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { - pr_debug("capture mode unspecified (%x)\n", + dev_dbg(pps->dev, "capture mode unspecified (%x)\n", params.mode); return -EINVAL; } /* Check for supported capabilities */ if ((params.mode & ~pps->info.mode) != 0) { - pr_debug("unsupported capabilities (%x)\n", + dev_dbg(pps->dev, "unsupported capabilities (%x)\n", params.mode); return -EINVAL; } @@ -115,7 +121,7 @@ static long pps_cdev_ioctl(struct file *file, /* Restore the read only parameters */ if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { /* section 3.3 of RFC 2783 interpreted */ - pr_debug("time format unspecified (%x)\n", + dev_dbg(pps->dev, "time format unspecified (%x)\n", params.mode); pps->params.mode |= PPS_TSFMT_TSPEC; } @@ -128,7 +134,7 @@ static long pps_cdev_ioctl(struct file *file, break; case PPS_GETCAP: - pr_debug("PPS_GETCAP: source %d\n", pps->id); + dev_dbg(pps->dev, "PPS_GETCAP\n"); err = put_user(pps->info.mode, iuarg); if (err) @@ -136,20 +142,26 @@ static long pps_cdev_ioctl(struct file *file, break; - case PPS_FETCH: - pr_debug("PPS_FETCH: source %d\n", pps->id); + case PPS_FETCH: { + struct pps_fdata fdata; + unsigned int ev; + + dev_dbg(pps->dev, "PPS_FETCH\n"); err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata)); if (err) return -EFAULT; - pps->go = 0; + ev = pps->last_ev; /* Manage the timeout */ if (fdata.timeout.flags & PPS_TIME_INVALID) - err = wait_event_interruptible(pps->queue, pps->go); + err = wait_event_interruptible(pps->queue, + ev != pps->last_ev); else { - pr_debug("timeout %lld.%09d\n", + unsigned long ticks; + + dev_dbg(pps->dev, "timeout %lld.%09d\n", (long long) fdata.timeout.sec, fdata.timeout.nsec); ticks = fdata.timeout.sec * HZ; @@ -157,7 +169,9 @@ static long pps_cdev_ioctl(struct file *file, if (ticks != 0) { err = wait_event_interruptible_timeout( - pps->queue, pps->go, ticks); + pps->queue, + ev != pps->last_ev, + ticks); if (err == 0) return -ETIMEDOUT; } @@ -165,7 +179,7 @@ static long pps_cdev_ioctl(struct file *file, /* Check for pending signals */ if (err == -ERESTARTSYS) { - pr_debug("pending signal caught\n"); + dev_dbg(pps->dev, "pending signal caught\n"); return -EINTR; } @@ -185,10 +199,44 @@ static long pps_cdev_ioctl(struct file *file, return -EFAULT; break; + } + case PPS_KC_BIND: { + struct pps_bind_args bind_args; + + dev_dbg(pps->dev, "PPS_KC_BIND\n"); + + /* Check the capabilities */ + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (copy_from_user(&bind_args, uarg, + sizeof(struct pps_bind_args))) + return -EFAULT; + /* Check for supported capabilities */ + if ((bind_args.edge & ~pps->info.mode) != 0) { + dev_err(pps->dev, "unsupported capabilities (%x)\n", + bind_args.edge); + return -EINVAL; + } + + /* Validate parameters roughly */ + if (bind_args.tsformat != PPS_TSFMT_TSPEC || + (bind_args.edge & ~PPS_CAPTUREBOTH) != 0 || + bind_args.consumer != PPS_KC_HARDPPS) { + dev_err(pps->dev, "invalid kernel consumer bind" + " parameters (%x)\n", bind_args.edge); + return -EINVAL; + } + + err = pps_kc_bind(pps, &bind_args); + if (err < 0) + return err; + + break; + } default: return -ENOTTY; - break; } return 0; @@ -198,12 +246,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file) { struct pps_device *pps = container_of(inode->i_cdev, struct pps_device, cdev); - int found; - - found = pps_get_source(pps->id) != 0; - if (!found) - return -ENODEV; - file->private_data = pps; return 0; @@ -211,11 +253,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file) static int pps_cdev_release(struct inode *inode, struct file *file) { - struct pps_device *pps = file->private_data; - - /* Free the PPS source and wake up (possible) deregistration */ - pps_put_source(pps); - return 0; } @@ -233,25 +270,67 @@ static const struct file_operations pps_cdev_fops = { .release = pps_cdev_release, }; +static void pps_device_destruct(struct device *dev) +{ + struct pps_device *pps = dev_get_drvdata(dev); + + /* release id here to protect others from using it while it's + * still in use */ + mutex_lock(&pps_idr_lock); + idr_remove(&pps_idr, pps->id); + mutex_unlock(&pps_idr_lock); + + kfree(dev); + kfree(pps); +} + int pps_register_cdev(struct pps_device *pps) { int err; + dev_t devt; + + mutex_lock(&pps_idr_lock); + /* Get new ID for the new PPS source */ + if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { + mutex_unlock(&pps_idr_lock); + return -ENOMEM; + } + + /* Now really allocate the PPS source. + * After idr_get_new() calling the new source will be freely available + * into the kernel. + */ + err = idr_get_new(&pps_idr, pps, &pps->id); + mutex_unlock(&pps_idr_lock); + + if (err < 0) + return err; + + pps->id &= MAX_ID_MASK; + if (pps->id >= PPS_MAX_SOURCES) { + pr_err("%s: too many PPS sources in the system\n", + pps->info.name); + err = -EBUSY; + goto free_idr; + } + + devt = MKDEV(MAJOR(pps_devt), pps->id); - pps->devno = MKDEV(MAJOR(pps_devt), pps->id); cdev_init(&pps->cdev, &pps_cdev_fops); pps->cdev.owner = pps->info.owner; - err = cdev_add(&pps->cdev, pps->devno, 1); + err = cdev_add(&pps->cdev, devt, 1); if (err) { - printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n", + pr_err("%s: failed to add char device %d:%d\n", pps->info.name, MAJOR(pps_devt), pps->id); - return err; + goto free_idr; } - pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL, + pps->dev = device_create(pps_class, pps->info.dev, devt, pps, "pps%d", pps->id); if (IS_ERR(pps->dev)) goto del_cdev; - dev_set_drvdata(pps->dev, pps); + + pps->dev->release = pps_device_destruct; pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, MAJOR(pps_devt), pps->id); @@ -261,12 +340,17 @@ int pps_register_cdev(struct pps_device *pps) del_cdev: cdev_del(&pps->cdev); +free_idr: + mutex_lock(&pps_idr_lock); + idr_remove(&pps_idr, pps->id); + mutex_unlock(&pps_idr_lock); + return err; } void pps_unregister_cdev(struct pps_device *pps) { - device_destroy(pps_class, pps->devno); + device_destroy(pps_class, pps->dev->devt); cdev_del(&pps->cdev); } @@ -286,14 +370,14 @@ static int __init pps_init(void) pps_class = class_create(THIS_MODULE, "pps"); if (!pps_class) { - printk(KERN_ERR "pps: failed to allocate class\n"); + pr_err("failed to allocate class\n"); return -ENOMEM; } pps_class->dev_attrs = pps_attrs; err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps"); if (err < 0) { - printk(KERN_ERR "pps: failed to allocate char device region\n"); + pr_err("failed to allocate char device region\n"); goto remove_class; } diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 1eb82c4c712e..467e82bd0929 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -46,7 +46,6 @@ static void rio_init_em(struct rio_dev *rdev); DEFINE_SPINLOCK(rio_global_list_lock); static int next_destid = 0; -static int next_switchid = 0; static int next_net = 0; static int next_comptag = 1; @@ -378,12 +377,30 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, struct rio_dev *rdev; struct rio_switch *rswitch = NULL; int result, rdid; + size_t size; + u32 swpinfo = 0; - rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); + size = sizeof(struct rio_dev); + if (rio_mport_read_config_32(port, destid, hopcount, + RIO_PEF_CAR, &result)) + return NULL; + + if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { + rio_mport_read_config_32(port, destid, hopcount, + RIO_SWP_INFO_CAR, &swpinfo); + if (result & RIO_PEF_SWITCH) { + size += (RIO_GET_TOTAL_PORTS(swpinfo) * + sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); + } + } + + rdev = kzalloc(size, GFP_KERNEL); if (!rdev) return NULL; rdev->net = net; + rdev->pef = result; + rdev->swpinfo = swpinfo; rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, &result); rdev->did = result >> 16; @@ -397,8 +414,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, &result); rdev->asm_rev = result >> 16; - rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, - &rdev->pef); if (rdev->pef & RIO_PEF_EXT_FEATURES) { rdev->efptr = result & 0xffff; rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, @@ -408,11 +423,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, hopcount, RIO_EFB_ERR_MGMNT); } - if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { - rio_mport_read_config_32(port, destid, hopcount, - RIO_SWP_INFO_CAR, &rdev->swpinfo); - } - rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, &rdev->src_ops); rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, @@ -427,6 +437,10 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, rio_mport_write_config_32(port, destid, hopcount, RIO_COMPONENT_TAG_CSR, next_comptag); rdev->comp_tag = next_comptag++; + } else { + rio_mport_read_config_32(port, destid, hopcount, + RIO_COMPONENT_TAG_CSR, + &rdev->comp_tag); } if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { @@ -437,21 +451,20 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, next_destid++; } else rdev->destid = rio_get_device_id(port, destid, hopcount); - } else - /* Switch device has an associated destID */ - rdev->destid = RIO_INVALID_DESTID; + + rdev->hopcount = 0xff; + } else { + /* Switch device has an associated destID which + * will be adjusted later + */ + rdev->destid = destid; + rdev->hopcount = hopcount; + } /* If a PE has both switch and other functions, show it as a switch */ if (rio_is_switch(rdev)) { - rswitch = kzalloc(sizeof(*rswitch) + - RIO_GET_TOTAL_PORTS(rdev->swpinfo) * - sizeof(rswitch->nextdev[0]), - GFP_KERNEL); - if (!rswitch) - goto cleanup; - rswitch->switchid = next_switchid; - rswitch->hopcount = hopcount; - rswitch->destid = destid; + rswitch = rdev->rswitch; + rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID; rswitch->port_ok = 0; rswitch->route_table = kzalloc(sizeof(u8)* RIO_MAX_ROUTE_ENTRIES(port->sys_size), @@ -462,15 +475,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); rdid++) rswitch->route_table[rdid] = RIO_INVALID_ROUTE; - rdev->rswitch = rswitch; - rswitch->rdev = rdev; dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, - rdev->rswitch->switchid); + rswitch->switchid); rio_switch_init(rdev, do_enum); - if (do_enum && rdev->rswitch->clr_table) - rdev->rswitch->clr_table(port, destid, hopcount, - RIO_GLOBAL_TABLE); + if (do_enum && rswitch->clr_table) + rswitch->clr_table(port, destid, hopcount, + RIO_GLOBAL_TABLE); list_add_tail(&rswitch->node, &rio_switches); @@ -506,10 +517,9 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, return rdev; cleanup: - if (rswitch) { + if (rswitch->route_table) kfree(rswitch->route_table); - kfree(rswitch); - } + kfree(rdev); return NULL; } @@ -632,8 +642,7 @@ rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) /** * rio_route_add_entry- Add a route entry to a switch routing table - * @mport: Master port to send transaction - * @rswitch: Switch device + * @rdev: RIO device * @table: Routing table ID * @route_destid: Destination ID to be routed * @route_port: Port number to be routed @@ -647,31 +656,31 @@ rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) * on failure. */ static int -rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, +rio_route_add_entry(struct rio_dev *rdev, u16 table, u16 route_destid, u8 route_port, int lock) { int rc; if (lock) { - rc = rio_lock_device(mport, rswitch->destid, - rswitch->hopcount, 1000); + rc = rio_lock_device(rdev->net->hport, rdev->destid, + rdev->hopcount, 1000); if (rc) return rc; } - rc = rswitch->add_entry(mport, rswitch->destid, - rswitch->hopcount, table, - route_destid, route_port); + rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid, + rdev->hopcount, table, + route_destid, route_port); if (lock) - rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); + rio_unlock_device(rdev->net->hport, rdev->destid, + rdev->hopcount); return rc; } /** * rio_route_get_entry- Read a route entry in a switch routing table - * @mport: Master port to send transaction - * @rswitch: Switch device + * @rdev: RIO device * @table: Routing table ID * @route_destid: Destination ID to be routed * @route_port: Pointer to read port number into @@ -685,23 +694,24 @@ rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, * on failure. */ static int -rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, +rio_route_get_entry(struct rio_dev *rdev, u16 table, u16 route_destid, u8 *route_port, int lock) { int rc; if (lock) { - rc = rio_lock_device(mport, rswitch->destid, - rswitch->hopcount, 1000); + rc = rio_lock_device(rdev->net->hport, rdev->destid, + rdev->hopcount, 1000); if (rc) return rc; } - rc = rswitch->get_entry(mport, rswitch->destid, - rswitch->hopcount, table, - route_destid, route_port); + rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid, + rdev->hopcount, table, + route_destid, route_port); if (lock) - rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); + rio_unlock_device(rdev->net->hport, rdev->destid, + rdev->hopcount); return rc; } @@ -809,16 +819,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, return -1; if (rio_is_switch(rdev)) { - next_switchid++; sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); - rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, port->host_deviceid, sw_inport, 0); rdev->rswitch->route_table[port->host_deviceid] = sw_inport; for (destid = 0; destid < next_destid; destid++) { if (destid == port->host_deviceid) continue; - rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, destid, sw_inport, 0); rdev->rswitch->route_table[destid] = sw_inport; } @@ -850,8 +859,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, "RIO: scanning device on port %d\n", port_num); rdev->rswitch->port_ok |= (1 << port_num); - rio_route_add_entry(port, rdev->rswitch, - RIO_GLOBAL_TABLE, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, RIO_ANY_DESTID(port->sys_size), port_num, 0); @@ -865,7 +873,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, destid < next_destid; destid++) { if (destid == port->host_deviceid) continue; - rio_route_add_entry(port, rdev->rswitch, + rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, destid, port_num, @@ -904,7 +912,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, next_destid++; } - rdev->rswitch->destid = sw_destid; + rdev->destid = sw_destid; } else pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", rio_name(rdev), rdev->vid, rdev->did); @@ -941,7 +949,7 @@ static int rio_enum_complete(struct rio_mport *port) */ static int __devinit rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, - u8 hopcount) + u8 hopcount, struct rio_dev *prev, int prev_port) { u8 port_num, route_port; struct rio_dev *rdev; @@ -951,14 +959,15 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { /* Add device to the global and bus/net specific list. */ list_add_tail(&rdev->net_list, &net->devices); + rdev->prev = prev; + if (prev && rio_is_switch(prev)) + prev->rswitch->nextdev[prev_port] = rdev; } else return -1; if (rio_is_switch(rdev)) { - next_switchid++; - /* Associated destid is how we accessed this switch */ - rdev->rswitch->destid = destid; + rdev->destid = destid; pr_debug( "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", @@ -981,7 +990,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, for (ndestid = 0; ndestid < RIO_ANY_DESTID(port->sys_size); ndestid++) { - rio_route_get_entry(port, rdev->rswitch, + rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, ndestid, &route_port, 0); @@ -992,8 +1001,8 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, if (ndestid == RIO_ANY_DESTID(port->sys_size)) continue; rio_unlock_device(port, destid, hopcount); - if (rio_disc_peer - (net, port, ndestid, hopcount + 1) < 0) + if (rio_disc_peer(net, port, ndestid, + hopcount + 1, rdev, port_num) < 0) return -1; } } @@ -1069,14 +1078,14 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) */ static void rio_update_route_tables(struct rio_mport *port) { - struct rio_dev *rdev; + struct rio_dev *rdev, *swrdev; struct rio_switch *rswitch; u8 sport; u16 destid; list_for_each_entry(rdev, &rio_devices, global_list) { - destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid; + destid = rdev->destid; list_for_each_entry(rswitch, &rio_switches, node) { @@ -1084,14 +1093,16 @@ static void rio_update_route_tables(struct rio_mport *port) continue; if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { + swrdev = sw_to_rio_dev(rswitch); + /* Skip if destid ends in empty switch*/ - if (rswitch->destid == destid) + if (swrdev->destid == destid) continue; - sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo); + sport = RIO_GET_PORT_NUM(swrdev->swpinfo); if (rswitch->add_entry) { - rio_route_add_entry(port, rswitch, + rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE, destid, sport, 0); rswitch->route_table[destid] = sport; @@ -1203,21 +1214,20 @@ static void rio_build_route_tables(void) list_for_each_entry(rdev, &rio_devices, global_list) if (rio_is_switch(rdev)) { - rio_lock_device(rdev->net->hport, rdev->rswitch->destid, - rdev->rswitch->hopcount, 1000); + rio_lock_device(rdev->net->hport, rdev->destid, + rdev->hopcount, 1000); for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); i++) { - if (rio_route_get_entry - (rdev->net->hport, rdev->rswitch, - RIO_GLOBAL_TABLE, i, &sport, 0) < 0) + if (rio_route_get_entry(rdev, + RIO_GLOBAL_TABLE, i, &sport, 0) < 0) continue; rdev->rswitch->route_table[i] = sport; } rio_unlock_device(rdev->net->hport, - rdev->rswitch->destid, - rdev->rswitch->hopcount); + rdev->destid, + rdev->hopcount); } } @@ -1284,7 +1294,7 @@ int __devinit rio_disc_mport(struct rio_mport *mport) mport->host_deviceid); if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), - 0) < 0) { + 0, NULL, 0) < 0) { printk(KERN_INFO "RIO: master port %d device has failed discovery\n", mport->id); diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 137ed93ee33f..76b41853a877 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -217,7 +217,7 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) err = device_create_bin_file(&rdev->dev, &rio_config_attr); - if (!err && rdev->rswitch) { + if (!err && (rdev->pef & RIO_PEF_SWITCH)) { err = device_create_file(&rdev->dev, &dev_attr_routes); if (!err && rdev->rswitch->sw_sysfs) err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE); @@ -239,7 +239,7 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) void rio_remove_sysfs_dev_files(struct rio_dev *rdev) { device_remove_bin_file(&rdev->dev, &rio_config_attr); - if (rdev->rswitch) { + if (rdev->pef & RIO_PEF_SWITCH) { device_remove_file(&rdev->dev, &dev_attr_routes); if (rdev->rswitch->sw_sysfs) rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 7b5080c45569..cc2a3b74d0f0 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -471,16 +471,9 @@ exit: */ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; u32 regval; - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - rio_mport_read_config_32(rdev->net->hport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), ®val); if (lock) @@ -488,7 +481,7 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) else regval &= ~RIO_PORT_N_CTL_LOCKOUT; - rio_mport_write_config_32(rdev->net->hport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), regval); return 0; @@ -507,7 +500,7 @@ static int rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) { u32 result; - int p_port, dstid, rc = -EIO; + int p_port, rc = -EIO; struct rio_dev *prev = NULL; /* Find switch with failed RIO link */ @@ -522,9 +515,7 @@ rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) if (prev == NULL) goto err_out; - dstid = (rdev->pef & RIO_PEF_SWITCH) ? - rdev->rswitch->destid : rdev->destid; - p_port = prev->rswitch->route_table[dstid]; + p_port = prev->rswitch->route_table[rdev->destid]; if (p_port != RIO_INVALID_ROUTE) { pr_debug("RIO: link failed on [%s]-P%d\n", @@ -567,15 +558,8 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) */ static int rio_chk_dev_access(struct rio_dev *rdev) { - u8 hopcount = 0xff; - u16 destid = rdev->destid; - - if (rdev->rswitch) { - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - } - - return rio_mport_chk_dev_access(rdev->net->hport, destid, hopcount); + return rio_mport_chk_dev_access(rdev->net->hport, + rdev->destid, rdev->hopcount); } /** @@ -588,23 +572,20 @@ static int rio_chk_dev_access(struct rio_dev *rdev) static int rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int checkcount; if (lnkresp) { /* Read from link maintenance response register * to clear valid bit */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), ®val); udelay(50); } /* Issue Input-status command */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), RIO_MNT_REQ_CMD_IS); @@ -615,7 +596,7 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) checkcount = 3; while (checkcount--) { udelay(50); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), ®val); if (regval & RIO_PORT_N_MNT_RSP_RVAL) { @@ -635,15 +616,12 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) */ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; u32 regval; u32 far_ackid, far_linkstat, near_ackid; if (err_status == 0) - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), &err_status); @@ -661,7 +639,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) pnum, regval); far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), ®val); pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); @@ -679,9 +657,8 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) /* Align near outstanding/outbound ackIDs with * far inbound. */ - rio_mport_write_config_32(mport, destid, - hopcount, rdev->phys_efptr + - RIO_PORT_N_ACK_STS_CSR(pnum), + rio_write_config_32(rdev, + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), (near_ackid << 24) | (far_ackid << 8) | far_ackid); /* Align far outstanding/outbound ackIDs with @@ -698,7 +675,7 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); } rd_err: - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), &err_status); pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); @@ -710,7 +687,7 @@ rd_err: RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); udelay(50); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), &err_status); pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); @@ -730,13 +707,10 @@ rd_err: int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) { struct rio_dev *rdev; - struct rio_mport *mport; - u8 hopcount; - u16 destid; u32 err_status, em_perrdet, em_ltlerrdet; int rc, portnum; - rdev = rio_get_comptag(pw_msg->em.comptag, NULL); + rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); if (rdev == NULL) { /* Device removed or enumeration error */ pr_debug("RIO: %s No matching device for CTag 0x%08x\n", @@ -800,17 +774,13 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) return 0; } - mport = rdev->net->hport; - destid = rdev->rswitch->destid; - hopcount = rdev->rswitch->hopcount; - /* * Process the port-write notification from switch */ if (rdev->rswitch->em_handle) rdev->rswitch->em_handle(rdev, portnum); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), &err_status); pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); @@ -840,7 +810,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) rdev->rswitch->port_ok &= ~(1 << portnum); rio_set_port_lockout(rdev, portnum, 1); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(portnum), RIO_PORT_N_ACK_CLEAR); @@ -851,28 +821,28 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) } } - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); if (em_perrdet) { pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", portnum, em_perrdet); /* Clear EM Port N Error Detect CSR */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); } - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); if (em_ltlerrdet) { pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", em_ltlerrdet); /* Clear EM L/T Layer Error Detect CSR */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); } /* Clear remaining error bits and Port-Write Pending bit */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), err_status); diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index 0bb871cb5c40..095016a9dec1 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -209,9 +209,6 @@ idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int idtg2_em_init(struct rio_dev *rdev) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int i, tmp; @@ -220,29 +217,25 @@ idtg2_em_init(struct rio_dev *rdev) * All standard EM configuration should be performed at upper level. */ - pr_debug("RIO: %s [%d:%d]\n", __func__, destid, hopcount); + pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); /* Set Port-Write info CSR: PRIO=3 and CRF=1 */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_PW_INFO_CSR, 0x0000e000); + rio_write_config_32(rdev, IDT_PW_INFO_CSR, 0x0000e000); /* * Configure LT LAYER error reporting. */ /* Enable standard (RIO.p8) error reporting */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_LT_ERR_REPORT_EN, + rio_write_config_32(rdev, IDT_LT_ERR_REPORT_EN, REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR | REM_LTL_ERR_UNSUPTR); /* Use Port-Writes for LT layer error reporting. * Enable per-port reset */ - rio_mport_read_config_32(mport, destid, hopcount, - IDT_DEV_CTRL_1, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_DEV_CTRL_1, + rio_read_config_32(rdev, IDT_DEV_CTRL_1, ®val); + rio_write_config_32(rdev, IDT_DEV_CTRL_1, regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH); /* @@ -250,45 +243,40 @@ idtg2_em_init(struct rio_dev *rdev) */ /* Report all RIO.p8 errors supported by device */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037); + rio_write_config_32(rdev, IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037); /* Configure reporting of implementation specific errors/events */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_PORT_ISERR_REPORT_EN_BC, IDT_PORT_INIT_TX_ACQUIRED); + rio_write_config_32(rdev, IDT_PORT_ISERR_REPORT_EN_BC, + IDT_PORT_INIT_TX_ACQUIRED); /* Use Port-Writes for port error reporting and enable error logging */ tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); for (i = 0; i < tmp; i++) { - rio_mport_read_config_32(mport, destid, hopcount, - IDT_PORT_OPS(i), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, IDT_PORT_OPS(i), ®val); + rio_write_config_32(rdev, IDT_PORT_OPS(i), regval | IDT_PORT_OPS_GENPW | IDT_PORT_OPS_PL_ELOG | IDT_PORT_OPS_LL_ELOG | IDT_PORT_OPS_LT_ELOG); } /* Overwrite error log if full */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); + rio_write_config_32(rdev, IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); /* * Configure LANE error reporting. */ /* Disable line error reporting */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_LANE_ERR_REPORT_EN_BC, 0); + rio_write_config_32(rdev, IDT_LANE_ERR_REPORT_EN_BC, 0); /* Use Port-Writes for lane error reporting (when enabled) * (do per-lane update because lanes may have different configuration) */ tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16; for (i = 0; i < tmp; i++) { - rio_mport_read_config_32(mport, destid, hopcount, - IDT_LANE_CTRL(i), ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_LANE_CTRL(i), regval | IDT_LANE_CTRL_GENPW); + rio_read_config_32(rdev, IDT_LANE_CTRL(i), ®val); + rio_write_config_32(rdev, IDT_LANE_CTRL(i), + regval | IDT_LANE_CTRL_GENPW); } /* @@ -296,41 +284,32 @@ idtg2_em_init(struct rio_dev *rdev) */ /* Disable JTAG and I2C Error capture */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_AUX_PORT_ERR_CAP_EN, 0); + rio_write_config_32(rdev, IDT_AUX_PORT_ERR_CAP_EN, 0); /* Disable JTAG and I2C Error reporting/logging */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_AUX_ERR_REPORT_EN, 0); + rio_write_config_32(rdev, IDT_AUX_ERR_REPORT_EN, 0); /* Disable Port-Write notification from JTAG */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_JTAG_CTRL, 0); + rio_write_config_32(rdev, IDT_JTAG_CTRL, 0); /* Disable Port-Write notification from I2C */ - rio_mport_read_config_32(mport, destid, hopcount, - IDT_I2C_MCTRL, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_I2C_MCTRL, - regval & ~IDT_I2C_MCTRL_GENPW); + rio_read_config_32(rdev, IDT_I2C_MCTRL, ®val); + rio_write_config_32(rdev, IDT_I2C_MCTRL, regval & ~IDT_I2C_MCTRL_GENPW); /* * Configure CFG_BLK error reporting. */ /* Disable Configuration Block error capture */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_CFGBLK_ERR_CAPTURE_EN, 0); + rio_write_config_32(rdev, IDT_CFGBLK_ERR_CAPTURE_EN, 0); /* Disable Port-Writes for Configuration Block error reporting */ - rio_mport_read_config_32(mport, destid, hopcount, - IDT_CFGBLK_ERR_REPORT, ®val); - rio_mport_write_config_32(mport, destid, hopcount, - IDT_CFGBLK_ERR_REPORT, - regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); + rio_read_config_32(rdev, IDT_CFGBLK_ERR_REPORT, ®val); + rio_write_config_32(rdev, IDT_CFGBLK_ERR_REPORT, + regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); /* set TVAL = ~50us */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); return 0; @@ -339,18 +318,15 @@ idtg2_em_init(struct rio_dev *rdev) static int idtg2_em_handler(struct rio_dev *rdev, u8 portnum) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval, em_perrdet, em_ltlerrdet; - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); if (em_ltlerrdet) { /* Service Logical/Transport Layer Error(s) */ if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) { /* Implementation specific error reported */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, ®val); pr_debug("RIO: %s Implementation Specific LTL errors" \ @@ -358,13 +334,12 @@ idtg2_em_handler(struct rio_dev *rdev, u8 portnum) rio_name(rdev), em_ltlerrdet, regval); /* Clear implementation specific address capture CSR */ - rio_mport_write_config_32(mport, destid, hopcount, - IDT_ISLTL_ADDRESS_CAP, 0); + rio_write_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, 0); } } - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); if (em_perrdet) { /* Service Port-Level Error(s) */ @@ -372,14 +347,14 @@ idtg2_em_handler(struct rio_dev *rdev, u8 portnum) /* Implementation Specific port error reported */ /* Get IS errors reported */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, IDT_PORT_ISERR_DET(portnum), ®val); pr_debug("RIO: %s Implementation Specific Port" \ " errors 0x%x\n", rio_name(rdev), regval); /* Clear all implementation specific events */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, IDT_PORT_ISERR_DET(portnum), 0); } } @@ -391,14 +366,10 @@ static ssize_t idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf) { struct rio_dev *rdev = to_rio_dev(dev); - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; ssize_t len = 0; u32 regval; - while (!rio_mport_read_config_32(mport, destid, hopcount, - IDT_ERR_RD, ®val)) { + while (!rio_read_config_32(rdev, IDT_ERR_RD, ®val)) { if (!regval) /* 0 = end of log */ break; len += snprintf(buf + len, PAGE_SIZE - len, @@ -445,3 +416,5 @@ static int idtg2_switch_init(struct rio_dev *rdev, int do_enum) DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init); DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init); +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init); +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init); diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c index fc9f6374f759..3a971077e7bf 100644 --- a/drivers/rapidio/switches/idtcps.c +++ b/drivers/rapidio/switches/idtcps.c @@ -117,10 +117,6 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; - pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); rdev->rswitch->add_entry = idtcps_route_add_entry; rdev->rswitch->get_entry = idtcps_route_get_entry; @@ -132,7 +128,7 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum) if (do_enum) { /* set TVAL = ~50us */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); } diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c index b9a389b9f812..3994c00aa01f 100644 --- a/drivers/rapidio/switches/tsi568.c +++ b/drivers/rapidio/switches/tsi568.c @@ -113,22 +113,17 @@ tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, static int tsi568_em_init(struct rio_dev *rdev) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int portnum; - pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount); + pr_debug("TSI568 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); /* Make sure that Port-Writes are disabled (for all ports) */ for (portnum = 0; portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { - rio_mport_read_config_32(mport, destid, hopcount, - TSI568_SP_MODE(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, - TSI568_SP_MODE(portnum), - regval | TSI568_SP_MODE_PW_DIS); + rio_read_config_32(rdev, TSI568_SP_MODE(portnum), ®val); + rio_write_config_32(rdev, TSI568_SP_MODE(portnum), + regval | TSI568_SP_MODE_PW_DIS); } return 0; diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c index 2003fb63c404..1a62934bfebc 100644 --- a/drivers/rapidio/switches/tsi57x.c +++ b/drivers/rapidio/switches/tsi57x.c @@ -158,48 +158,45 @@ tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, static int tsi57x_em_init(struct rio_dev *rdev) { - struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 regval; int portnum; - pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount); + pr_debug("TSI578 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); for (portnum = 0; portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) { /* Make sure that Port-Writes are enabled (for all ports) */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_MODE(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_MODE(portnum), regval & ~TSI578_SP_MODE_PW_DIS); /* Clear all pending interrupts */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), regval & 0x07120214); - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum), regval & 0x000700bd); /* Enable all interrupts to allow ports to send a port-write */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_CTL_INDEP(portnum), ®val); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_CTL_INDEP(portnum), regval | 0x000b0000); /* Skip next (odd) port if the current port is in x4 mode */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), ®val); if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4) @@ -207,7 +204,7 @@ tsi57x_em_init(struct rio_dev *rdev) } /* set TVAL = ~50us */ - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x9a << 8); return 0; @@ -217,14 +214,12 @@ static int tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) { struct rio_mport *mport = rdev->net->hport; - u16 destid = rdev->rswitch->destid; - u8 hopcount = rdev->rswitch->hopcount; u32 intstat, err_status; int sendcount, checkcount; u8 route_port; u32 regval; - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), &err_status); @@ -232,15 +227,15 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | RIO_PORT_N_ERR_STS_PW_INP_ES))) { /* Remove any queued packets by locking/unlocking port */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), ®val); if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) { - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), regval | RIO_PORT_N_CTL_LOCKOUT); udelay(50); - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum), regval); } @@ -248,7 +243,7 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) /* Read from link maintenance response register to clear * valid bit */ - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum), ®val); @@ -257,13 +252,12 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) */ sendcount = 3; while (sendcount) { - rio_mport_write_config_32(mport, destid, hopcount, + rio_write_config_32(rdev, TSI578_SP_CS_TX(portnum), 0x40fc8000); checkcount = 3; while (checkcount--) { udelay(50); - rio_mport_read_config_32( - mport, destid, hopcount, + rio_read_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum), ®val); @@ -277,25 +271,23 @@ tsi57x_em_handler(struct rio_dev *rdev, u8 portnum) exit_es: /* Clear implementation specific error status bits */ - rio_mport_read_config_32(mport, destid, hopcount, - TSI578_SP_INT_STATUS(portnum), &intstat); + rio_read_config_32(rdev, TSI578_SP_INT_STATUS(portnum), &intstat); pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n", - destid, hopcount, portnum, intstat); + rdev->destid, rdev->hopcount, portnum, intstat); if (intstat & 0x10000) { - rio_mport_read_config_32(mport, destid, hopcount, + rio_read_config_32(rdev, TSI578_SP_LUT_PEINF(portnum), ®val); regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24); route_port = rdev->rswitch->route_table[regval]; pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n", rio_name(rdev), portnum, regval); - tsi57x_route_add_entry(mport, destid, hopcount, + tsi57x_route_add_entry(mport, rdev->destid, rdev->hopcount, RIO_GLOBAL_TABLE, regval, route_port); } - rio_mport_write_config_32(mport, destid, hopcount, - TSI578_SP_INT_STATUS(portnum), - intstat & 0x000700bd); + rio_write_config_32(rdev, TSI578_SP_INT_STATUS(portnum), + intstat & 0x000700bd); return 0; } diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 2ce2eb71d0f5..dd6308499bd4 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -249,7 +249,7 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) } static int pm8607_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); uint8_t val, mask; @@ -263,6 +263,7 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, ret = choose_voltage(rdev, min_uV, max_uV); if (ret < 0) return -EINVAL; + *selector = ret; val = (uint8_t)(ret << info->vol_shift); mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dd30e883d4a7..e1d943619ab8 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -186,13 +186,25 @@ config REGULATOR_PCAP This driver provides support for the voltage regulators of the PCAP2 PMIC. +config REGULATOR_MC13XXX_CORE + tristate + config REGULATOR_MC13783 tristate "Support regulators on Freescale MC13783 PMIC" depends on MFD_MC13783 + select REGULATOR_MC13XXX_CORE help Say y here to support the regulators found on the Freescale MC13783 PMIC. +config REGULATOR_MC13892 + tristate "Support regulators on Freescale MC13892 PMIC" + depends on MFD_MC13XXX + select REGULATOR_MC13XXX_CORE + help + Say y here to support the regulators found on the Freescale MC13892 + PMIC. + config REGULATOR_AB3100 tristate "ST-Ericsson AB3100 Regulator functions" depends on AB3100_CORE @@ -250,5 +262,15 @@ config REGULATOR_TPS6586X help This driver supports TPS6586X voltage regulator chips. +config REGULATOR_TPS6524X + tristate "TI TPS6524X Power regulators" + depends on SPI + help + This driver supports TPS6524X voltage regulator chips. TPS6524X + provides three step-down converters and two general-purpose LDO + voltage regulators. This device is interfaced using a customized + serial interface currently supported on the sequencer serial + port controller. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bff815736780..0b5e88c2b8d7 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,10 +30,13 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o +obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o +obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o +obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index b349266a43de..ed6feaf9398d 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -362,7 +362,8 @@ static int ab3100_get_best_voltage_index(struct regulator_dev *reg, } static int ab3100_set_voltage_regulator(struct regulator_dev *reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct ab3100_regulator *abreg = reg->reg_data; u8 regval; @@ -373,6 +374,8 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg, if (bestindex < 0) return bestindex; + *selector = bestindex; + err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg, ®val); if (err) { diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index db6b70f20511..d9a052c53aec 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -3,18 +3,13 @@ * * License Terms: GNU General Public License v2 * - * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson + * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson * * AB8500 peripheral regulators * - * AB8500 supports the following regulators, - * LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT, - * VAUX1/2/3, VANA - * - * for DB8500 cut 1.0 and previous versions of the silicon, all accesses - * to registers are through the DB8500 SPI. In cut 1.1 onwards, these - * accesses are through the DB8500 PRCMU I2C - * + * AB8500 supports the following regulators: + * VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include <linux/init.h> #include <linux/kernel.h> @@ -28,38 +23,37 @@ /** * struct ab8500_regulator_info - ab8500 regulator information + * @dev: device pointer * @desc: regulator description - * @ab8500: ab8500 parent * @regulator_dev: regulator device * @max_uV: maximum voltage (for variable voltage supplies) * @min_uV: minimum voltage (for variable voltage supplies) * @fixed_uV: typical voltage (for fixed voltage supplies) * @update_bank: bank to control on/off * @update_reg: register to control on/off - * @mask: mask to enable/disable regulator - * @enable: bits to enable the regulator in normal(high power) mode + * @update_mask: mask to enable/disable regulator + * @update_val_enable: bits to enable the regulator in normal (high power) mode * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage - * @supported_voltages: supported voltage table + * @voltages: supported voltage table * @voltages_len: number of supported voltages for the regulator */ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; - struct ab8500 *ab8500; struct regulator_dev *regulator; int max_uV; int min_uV; int fixed_uV; u8 update_bank; u8 update_reg; - u8 mask; - u8 enable; + u8 update_mask; + u8 update_val_enable; u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; - int const *supported_voltages; + int const *voltages; int voltages_len; }; @@ -83,6 +77,17 @@ static const int ldo_vauxn_voltages[] = { 3300000, }; +static const int ldo_vaux3_voltages[] = { + 1200000, + 1500000, + 1800000, + 2100000, + 2500000, + 2750000, + 2790000, + 2910000, +}; + static const int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -95,57 +100,80 @@ static const int ldo_vintcore_voltages[] = { static int ab8500_regulator_enable(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, info->mask, info->enable); + info->update_bank, info->update_reg, + info->update_mask, info->update_val_enable); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); + + dev_vdbg(rdev_get_dev(rdev), + "%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, info->update_val_enable); + return ret; } static int ab8500_regulator_disable(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, info->mask, 0x0); + info->update_bank, info->update_reg, + info->update_mask, 0x0); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); + + dev_vdbg(rdev_get_dev(rdev), + "%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, 0x0); + return ret; } static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 value; + u8 regval; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_get_register_interruptible(info->dev, - info->update_bank, info->update_reg, &value); + info->update_bank, info->update_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read 0x%x register\n", info->update_reg); return ret; } - if (value & info->mask) + dev_vdbg(rdev_get_dev(rdev), + "%s-is_enabled (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," + " 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, regval); + + if (regval & info->update_mask) return true; else return false; @@ -153,12 +181,12 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) { - int regulator_id; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } /* return the uV for the fixed regulators */ if (info->fixed_uV) @@ -167,33 +195,40 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) if (selector >= info->voltages_len) return -EINVAL; - return info->supported_voltages[selector]; + return info->voltages[selector]; } static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret, val; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 value; + u8 regval; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } - ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, - info->voltage_reg, &value); + ret = abx500_get_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read voltage reg for regulator\n"); return ret; } + dev_vdbg(rdev_get_dev(rdev), + "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," + " 0x%x\n", + info->desc.name, info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + /* vintcore has a different layout */ - value &= info->voltage_mask; - if (regulator_id == AB8500_LDO_INTCORE) - ret = info->supported_voltages[value >> 0x3]; + val = regval & info->voltage_mask; + if (info->desc.id == AB8500_LDO_INTCORE) + ret = info->voltages[val >> 0x3]; else - ret = info->supported_voltages[value]; + ret = info->voltages[val]; return ret; } @@ -206,8 +241,8 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, /* check the supported voltage */ for (i = 0; i < info->voltages_len; i++) { - if ((info->supported_voltages[i] >= min_uV) && - (info->supported_voltages[i] <= max_uV)) + if ((info->voltages[i] >= min_uV) && + (info->voltages[i] <= max_uV)) return i; } @@ -215,14 +250,17 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, } static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } /* get the appropriate voltages within the range */ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV); @@ -232,14 +270,23 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, return ret; } + *selector = ret; + /* set the registers for the request */ + regval = (u8)ret; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->voltage_bank, info->voltage_reg, - info->voltage_mask, (u8)ret); + info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set voltage reg for regulator\n"); + dev_vdbg(rdev_get_dev(rdev), + "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x," + " 0x%x\n", + info->desc.name, info->voltage_bank, info->voltage_reg, + info->voltage_mask, regval); + return ret; } @@ -254,17 +301,17 @@ static struct regulator_ops ab8500_regulator_ops = { static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) { - int regulator_id; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } return info->fixed_uV; } -static struct regulator_ops ab8500_ldo_fixed_ops = { +static struct regulator_ops ab8500_regulator_fixed_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, @@ -272,88 +319,197 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, min, max, bank, reg, reg_mask, \ - reg_enable, volt_bank, volt_reg, volt_mask, \ - voltages, len_volts) \ -{ \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .min_uV = (min) * 1000, \ - .max_uV = (max) * 1000, \ - .update_bank = bank, \ - .update_reg = reg, \ - .mask = reg_mask, \ - .enable = reg_enable, \ - .voltage_bank = volt_bank, \ - .voltage_reg = volt_reg, \ - .voltage_mask = volt_mask, \ - .supported_voltages = voltages, \ - .voltages_len = len_volts, \ - .fixed_uV = 0, \ -} - -#define AB8500_FIXED_LDO(_id, fixed, bank, reg, \ - reg_mask, reg_enable) \ -{ \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_ldo_fixed_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .fixed_uV = fixed * 1000, \ - .update_bank = bank, \ - .update_reg = reg, \ - .mask = reg_mask, \ - .enable = reg_enable, \ -} - -static struct ab8500_regulator_info ab8500_regulator_info[] = { +static struct ab8500_regulator_info + ab8500_regulator_info[AB8500_NUM_REGULATORS] = { /* - * Variable Voltage LDOs - * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask, - * volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table, - * num supported volts + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask, table, table length */ - AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38, - ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), + [AB8500_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val_enable = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8500_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val_enable = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8500_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val_enable = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + .voltages = ldo_vaux3_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages), + }, + [AB8500_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val_enable = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + .voltages = ldo_vintcore_voltages, + .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages), + }, /* - * Fixed Voltage LDOs - * name, o/p uV, ctrl bank, ctrl reg, enable, disable + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x2, 0x2), - AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x4, 0x4), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x8, 0x8), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(ANA, 1200, 0x03, 0x83, 0xc, 0x4), -}; + [AB8500_LDO_TVOUT] = { + .desc = { + .name = "LDO-TVOUT", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_TVOUT, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val_enable = 0x02, + }, + [AB8500_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val_enable = 0x02, + }, + [AB8500_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val_enable = 0x08, + }, + [AB8500_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val_enable = 0x10, + }, + [AB8500_LDO_DMIC] = { + .desc = { + .name = "LDO-DMIC", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_DMIC, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1800000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val_enable = 0x04, + }, + [AB8500_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1200000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val_enable = 0x04, + }, -static inline struct ab8500_regulator_info *find_regulator_info(int id) -{ - struct ab8500_regulator_info *info; - int i; - for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { - info = &ab8500_regulator_info[i]; - if (info->desc.id == id) - return info; - } - return NULL; -} +}; static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { @@ -366,6 +522,16 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) return -EINVAL; } pdata = dev_get_platdata(ab8500->dev); + if (!pdata) { + dev_err(&pdev->dev, "null pdata\n"); + return -EINVAL; + } + + /* make sure the platform data has the correct size */ + if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { + dev_err(&pdev->dev, "platform configuration error\n"); + return -EINVAL; + } /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { @@ -374,10 +540,22 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) /* assign per-regulator data */ info = &ab8500_regulator_info[i]; info->dev = &pdev->dev; - info->ab8500 = ab8500; + /* fix for hardware before ab8500v2.0 */ + if (abx500_get_chip_id(info->dev) < 0x20) { + if (info->desc.id == AB8500_LDO_AUX3) { + info->desc.n_voltages = + ARRAY_SIZE(ldo_vauxn_voltages); + info->voltages = ldo_vauxn_voltages; + info->voltages_len = + ARRAY_SIZE(ldo_vauxn_voltages); + info->voltage_mask = 0xf; + } + } + + /* register regulator with framework */ info->regulator = regulator_register(&info->desc, &pdev->dev, - pdata->regulator[i], info); + &pdata->regulator[i], info); if (IS_ERR(info->regulator)) { err = PTR_ERR(info->regulator); dev_err(&pdev->dev, "failed to register regulator %s\n", @@ -389,6 +567,9 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) } return err; } + + dev_vdbg(rdev_get_dev(info->regulator), + "%s-probed\n", info->desc.name); } return 0; @@ -401,6 +582,10 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; info = &ab8500_regulator_info[i]; + + dev_vdbg(rdev_get_dev(info->regulator), + "%s-remove\n", info->desc.name); + regulator_unregister(info->regulator); } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ba521f0f0fac..9fa20957847d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -13,8 +13,11 @@ * */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + #include <linux/kernel.h> #include <linux/init.h> +#include <linux/debugfs.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/err.h> @@ -25,16 +28,30 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#define CREATE_TRACE_POINTS +#include <trace/events/regulator.h> + #include "dummy.h" -#define REGULATOR_VERSION "0.5" +#define rdev_err(rdev, fmt, ...) \ + pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_warn(rdev, fmt, ...) \ + pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_info(rdev, fmt, ...) \ + pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_dbg(rdev, fmt, ...) \ + pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); -static int has_full_constraints; +static bool has_full_constraints; static bool board_wants_dummy_regulator; +#ifdef CONFIG_DEBUG_FS +static struct dentry *debugfs_root; +#endif + /* * struct regulator_map * @@ -71,6 +88,8 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); +static int _regulator_do_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV); static const char *rdev_get_name(struct regulator_dev *rdev) { @@ -111,13 +130,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev, BUG_ON(*min_uV > *max_uV); if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } @@ -132,6 +149,27 @@ static int regulator_check_voltage(struct regulator_dev *rdev, return 0; } +/* Make sure we select a voltage that suits the needs of all + * regulator consumers + */ +static int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + struct regulator *regulator; + + list_for_each_entry(regulator, &rdev->consumer_list, list) { + if (*max_uV > regulator->max_uV) + *max_uV = regulator->max_uV; + if (*min_uV < regulator->min_uV) + *min_uV = regulator->min_uV; + } + + if (*min_uV > *max_uV) + return -EINVAL; + + return 0; +} + /* current constraint check */ static int regulator_check_current_limit(struct regulator_dev *rdev, int *min_uA, int *max_uA) @@ -139,13 +177,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, BUG_ON(*min_uA > *max_uA); if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } @@ -174,18 +210,15 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) } if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } if (!(rdev->constraints->valid_modes_mask & mode)) { - printk(KERN_ERR "%s: invalid mode %x for %s\n", - __func__, mode, rdev_get_name(rdev)); + rdev_err(rdev, "invalid mode %x\n", mode); return -EINVAL; } return 0; @@ -195,13 +228,11 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) static int regulator_check_drms(struct regulator_dev *rdev) { if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } return 0; @@ -553,18 +584,21 @@ static void drms_uA_update(struct regulator_dev *rdev) err = regulator_check_drms(rdev); if (err < 0 || !rdev->desc->ops->get_optimum_mode || - !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode) + (!rdev->desc->ops->get_voltage && + !rdev->desc->ops->get_voltage_sel) || + !rdev->desc->ops->set_mode) return; /* get output voltage */ - output_uV = rdev->desc->ops->get_voltage(rdev); + output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) return; /* get input voltage */ - if (rdev->supply && rdev->supply->desc->ops->get_voltage) - input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); - else + input_uV = 0; + if (rdev->supply) + input_uV = _regulator_get_voltage(rdev); + if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) return; @@ -598,20 +632,17 @@ static int suspend_set_state(struct regulator_dev *rdev, */ if (!rstate->enabled && !rstate->disabled) { if (can_set_state) - printk(KERN_WARNING "%s: No configuration for %s\n", - __func__, rdev_get_name(rdev)); + rdev_warn(rdev, "No configuration\n"); return 0; } if (rstate->enabled && rstate->disabled) { - printk(KERN_ERR "%s: invalid configuration for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "invalid configuration\n"); return -EINVAL; } if (!can_set_state) { - printk(KERN_ERR "%s: no way to set suspend state\n", - __func__); + rdev_err(rdev, "no way to set suspend state\n"); return -EINVAL; } @@ -620,15 +651,14 @@ static int suspend_set_state(struct regulator_dev *rdev, else ret = rdev->desc->ops->set_suspend_disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to enabled/disable\n", __func__); + rdev_err(rdev, "failed to enabled/disable\n"); return ret; } if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); if (ret < 0) { - printk(KERN_ERR "%s: failed to set voltage\n", - __func__); + rdev_err(rdev, "failed to set voltage\n"); return ret; } } @@ -636,7 +666,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to set mode\n", __func__); + rdev_err(rdev, "failed to set mode\n"); return ret; } } @@ -714,29 +744,27 @@ static void print_constraints(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += sprintf(buf + count, "standby"); - printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf); + rdev_info(rdev, "%s\n", buf); } static int machine_constraints_voltage(struct regulator_dev *rdev, struct regulation_constraints *constraints) { struct regulator_ops *ops = rdev->desc->ops; - const char *name = rdev_get_name(rdev); int ret; /* do we need to apply the constraint voltage */ if (rdev->constraints->apply_uV && - rdev->constraints->min_uV == rdev->constraints->max_uV && - ops->set_voltage) { - ret = ops->set_voltage(rdev, - rdev->constraints->min_uV, rdev->constraints->max_uV); - if (ret < 0) { - printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n", - __func__, - rdev->constraints->min_uV, name); - rdev->constraints = NULL; - return ret; - } + rdev->constraints->min_uV == rdev->constraints->max_uV) { + ret = _regulator_do_set_voltage(rdev, + rdev->constraints->min_uV, + rdev->constraints->max_uV); + if (ret < 0) { + rdev_err(rdev, "failed to apply %duV constraint\n", + rdev->constraints->min_uV); + rdev->constraints = NULL; + return ret; + } } /* constrain machine-level voltage specs to fit @@ -765,8 +793,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("%s: %s '%s' voltage constraints\n", - __func__, "invalid", name); + rdev_err(rdev, "invalid voltage constraints\n"); return -EINVAL; } @@ -787,22 +814,19 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("%s: %s '%s' voltage constraints\n", - __func__, "unsupportable", name); + rdev_err(rdev, "unsupportable voltage constraints\n"); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("%s: override '%s' %s, %d -> %d\n", - __func__, name, "min_uV", - constraints->min_uV, min_uV); + rdev_dbg(rdev, "override min_uV, %d -> %d\n", + constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("%s: override '%s' %s, %d -> %d\n", - __func__, name, "max_uV", - constraints->max_uV, max_uV); + rdev_dbg(rdev, "override max_uV, %d -> %d\n", + constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } @@ -822,26 +846,25 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, * set_mode. */ static int set_machine_constraints(struct regulator_dev *rdev, - struct regulation_constraints *constraints) + const struct regulation_constraints *constraints) { int ret = 0; - const char *name; struct regulator_ops *ops = rdev->desc->ops; - rdev->constraints = constraints; - - name = rdev_get_name(rdev); + rdev->constraints = kmemdup(constraints, sizeof(*constraints), + GFP_KERNEL); + if (!rdev->constraints) + return -ENOMEM; - ret = machine_constraints_voltage(rdev, constraints); + ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) goto out; /* do we need to setup our suspend state */ if (constraints->initial_state) { - ret = suspend_prepare(rdev, constraints->initial_state); + ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { - printk(KERN_ERR "%s: failed to set suspend state for %s\n", - __func__, name); + rdev_err(rdev, "failed to set suspend state\n"); rdev->constraints = NULL; goto out; } @@ -849,17 +872,14 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_mode) { if (!ops->set_mode) { - printk(KERN_ERR "%s: no set_mode operation for %s\n", - __func__, name); + rdev_err(rdev, "no set_mode operation\n"); ret = -EINVAL; goto out; } - ret = ops->set_mode(rdev, constraints->initial_mode); + ret = ops->set_mode(rdev, rdev->constraints->initial_mode); if (ret < 0) { - printk(KERN_ERR - "%s: failed to set initial mode for %s: %d\n", - __func__, name, ret); + rdev_err(rdev, "failed to set initial mode: %d\n", ret); goto out; } } @@ -867,11 +887,11 @@ static int set_machine_constraints(struct regulator_dev *rdev, /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ - if ((constraints->always_on || constraints->boot_on) && ops->enable) { + if ((rdev->constraints->always_on || rdev->constraints->boot_on) && + ops->enable) { ret = ops->enable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s\n", - __func__, name); + rdev_err(rdev, "failed to enable\n"); rdev->constraints = NULL; goto out; } @@ -899,9 +919,8 @@ static int set_supply(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, "supply"); if (err) { - printk(KERN_ERR - "%s: could not add device link %s err %d\n", - __func__, supply_rdev->dev.kobj.name, err); + rdev_err(rdev, "could not add device link %s err %d\n", + supply_rdev->dev.kobj.name, err); goto out; } rdev->supply = supply_rdev; @@ -957,10 +976,10 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, continue; dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n", - dev_name(&node->regulator->dev), - node->regulator->desc->name, - supply, - dev_name(&rdev->dev), rdev_get_name(rdev)); + dev_name(&node->regulator->dev), + node->regulator->desc->name, + supply, + dev_name(&rdev->dev), rdev_get_name(rdev)); return -EBUSY; } @@ -1031,8 +1050,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, regulator->dev_attr.show = device_requested_uA_show; err = device_create_file(dev, ®ulator->dev_attr); if (err < 0) { - printk(KERN_WARNING "%s: could not add regulator_dev" - " load sysfs\n", __func__); + rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n"); goto attr_name_err; } @@ -1049,9 +1067,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { - printk(KERN_WARNING - "%s: could not add device link %s err %d\n", - __func__, dev->kobj.name, err); + rdev_warn(rdev, "could not add device link %s err %d\n", + dev->kobj.name, err); goto link_name_err; } } @@ -1088,7 +1105,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, int ret; if (id == NULL) { - printk(KERN_ERR "regulator: get() with no identifier\n"); + pr_err("get() with no identifier\n"); return regulator; } @@ -1122,8 +1139,8 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * substitute in a dummy regulator so consumers can continue. */ if (!has_full_constraints) { - pr_warning("%s supply %s not found, using dummy regulator\n", - devname, id); + pr_warn("%s supply %s not found, using dummy regulator\n", + devname, id); rdev = dummy_regulator_rdev; goto found; } @@ -1274,8 +1291,7 @@ static int _regulator_enable(struct regulator_dev *rdev) ret = _regulator_enable(rdev->supply); mutex_unlock(&rdev->supply->mutex); if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); + rdev_err(rdev, "failed to enable: %d\n", ret); return ret; } } @@ -1302,13 +1318,13 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret >= 0) { delay = ret; } else { - printk(KERN_WARNING - "%s: enable_time() failed for %s: %d\n", - __func__, rdev_get_name(rdev), - ret); + rdev_warn(rdev, "enable_time() failed: %d\n", + ret); delay = 0; } + trace_regulator_enable(rdev_get_name(rdev)); + /* Allow the regulator to ramp; it would be useful * to extend this for bulk operations so that the * regulators can ramp together. */ @@ -1316,6 +1332,8 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret < 0) return ret; + trace_regulator_enable_delay(rdev_get_name(rdev)); + if (delay >= 1000) { mdelay(delay / 1000); udelay(delay % 1000); @@ -1323,9 +1341,10 @@ static int _regulator_enable(struct regulator_dev *rdev) udelay(delay); } + trace_regulator_enable_complete(rdev_get_name(rdev)); + } else if (ret < 0) { - printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", - __func__, rdev_get_name(rdev), ret); + rdev_err(rdev, "is_enabled() failed: %d\n", ret); return ret; } /* Fallthrough on positive return values - already enabled */ @@ -1367,8 +1386,7 @@ static int _regulator_disable(struct regulator_dev *rdev, *supply_rdev_ptr = NULL; if (WARN(rdev->use_count <= 0, - "unbalanced disables for %s\n", - rdev_get_name(rdev))) + "unbalanced disables for %s\n", rdev_get_name(rdev))) return -EIO; /* are we the last user and permitted to disable ? */ @@ -1378,13 +1396,16 @@ static int _regulator_disable(struct regulator_dev *rdev, /* we are last user */ if (_regulator_can_change_status(rdev) && rdev->desc->ops->disable) { + trace_regulator_disable(rdev_get_name(rdev)); + ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to disable %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "failed to disable\n"); return ret; } + trace_regulator_disable_complete(rdev_get_name(rdev)); + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, NULL); } @@ -1451,8 +1472,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev, /* ah well, who wants to live forever... */ ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to force disable %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "failed to force disable\n"); return ret; } /* notify other consumers that power has been forced off */ @@ -1605,6 +1625,62 @@ int regulator_is_supported_voltage(struct regulator *regulator, return 0; } +static int _regulator_do_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + unsigned int selector; + + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); + + if (rdev->desc->ops->set_voltage) { + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, + &selector); + + if (rdev->desc->ops->list_voltage) + selector = rdev->desc->ops->list_voltage(rdev, + selector); + else + selector = -1; + } else if (rdev->desc->ops->set_voltage_sel) { + int best_val = INT_MAX; + int i; + + selector = 0; + + /* Find the smallest voltage that falls within the specified + * range. + */ + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret < best_val && ret >= min_uV && ret <= max_uV) { + best_val = ret; + selector = i; + } + } + + if (best_val != INT_MAX) { + ret = rdev->desc->ops->set_voltage_sel(rdev, selector); + selector = best_val; + } else { + ret = -EINVAL; + } + } else { + ret = -EINVAL; + } + + if (ret == 0) + _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, + NULL); + + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + + return ret; +} + /** * regulator_set_voltage - set regulator output voltage * @regulator: regulator source @@ -1626,12 +1702,20 @@ int regulator_is_supported_voltage(struct regulator *regulator, int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; - int ret; + int ret = 0; mutex_lock(&rdev->mutex); + /* If we're setting the same range as last time the change + * should be a noop (some cpufreq implementations use the same + * voltage for multiple frequencies, for example). + */ + if (regulator->min_uV == min_uV && regulator->max_uV == max_uV) + goto out; + /* sanity check */ - if (!rdev->desc->ops->set_voltage) { + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { ret = -EINVAL; goto out; } @@ -1642,18 +1726,76 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) goto out; regulator->min_uV = min_uV; regulator->max_uV = max_uV; - ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV); + + ret = regulator_check_consumers(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: - _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_set_voltage); +/** + * regulator_sync_voltage - re-apply last regulator output voltage + * @regulator: regulator source + * + * Re-apply the last configured voltage. This is intended to be used + * where some external control source the consumer is cooperating with + * has caused the configured voltage to change. + */ +int regulator_sync_voltage(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret, min_uV, max_uV; + + mutex_lock(&rdev->mutex); + + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { + ret = -EINVAL; + goto out; + } + + /* This is only going to work if we've had a voltage configured. */ + if (!regulator->min_uV && !regulator->max_uV) { + ret = -EINVAL; + goto out; + } + + min_uV = regulator->min_uV; + max_uV = regulator->max_uV; + + /* This should be a paranoia check... */ + ret = regulator_check_voltage(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = regulator_check_consumers(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); + +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_sync_voltage); + static int _regulator_get_voltage(struct regulator_dev *rdev) { - /* sanity check */ + int sel; + + if (rdev->desc->ops->get_voltage_sel) { + sel = rdev->desc->ops->get_voltage_sel(rdev); + if (sel < 0) + return sel; + return rdev->desc->ops->list_voltage(rdev, sel); + } if (rdev->desc->ops->get_voltage) return rdev->desc->ops->get_voltage(rdev); else @@ -1880,21 +2022,20 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) goto out; /* get output voltage */ - output_uV = rdev->desc->ops->get_voltage(rdev); + output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) { - printk(KERN_ERR "%s: invalid output voltage found for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "invalid output voltage found\n"); goto out; } /* get input voltage */ - if (rdev->supply && rdev->supply->desc->ops->get_voltage) - input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); - else + input_uV = 0; + if (rdev->supply) + input_uV = _regulator_get_voltage(rdev->supply); + if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { - printk(KERN_ERR "%s: invalid input voltage found for %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "invalid input voltage found\n"); goto out; } @@ -1907,16 +2048,14 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) total_uA_load); ret = regulator_check_mode(rdev, mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to get optimum mode for %s @" - " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev), - total_uA_load, input_uV, output_uV); + rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", + total_uA_load, input_uV, output_uV); goto out; } ret = rdev->desc->ops->set_mode(rdev, mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n", - __func__, mode, rdev_get_name(rdev)); + rdev_err(rdev, "failed to set optimum mode %x\n", mode); goto out; } ret = mode; @@ -2047,7 +2186,7 @@ int regulator_bulk_enable(int num_consumers, return 0; err: - printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret); + pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); for (--i; i >= 0; --i) regulator_disable(consumers[i].consumer); @@ -2082,8 +2221,7 @@ int regulator_bulk_disable(int num_consumers, return 0; err: - printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply, - ret); + pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret); for (--i; i >= 0; --i) regulator_enable(consumers[i].consumer); @@ -2166,7 +2304,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) int status = 0; /* some attributes need specific methods to be displayed */ - if (ops->get_voltage) { + if (ops->get_voltage || ops->get_voltage_sel) { status = device_create_file(dev, &dev_attr_microvolts); if (status < 0) return status; @@ -2207,7 +2345,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; /* constraints need specific supporting methods */ - if (ops->set_voltage) { + if (ops->set_voltage || ops->set_voltage_sel) { status = device_create_file(dev, &dev_attr_min_microvolts); if (status < 0) return status; @@ -2271,6 +2409,23 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; } +static void rdev_init_debugfs(struct regulator_dev *rdev) +{ +#ifdef CONFIG_DEBUG_FS + rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); + if (IS_ERR(rdev->debugfs) || !rdev->debugfs) { + rdev_warn(rdev, "Failed to create debugfs directory\n"); + rdev->debugfs = NULL; + return; + } + + debugfs_create_u32("use_count", 0444, rdev->debugfs, + &rdev->use_count); + debugfs_create_u32("open_count", 0444, rdev->debugfs, + &rdev->open_count); +#endif +} + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -2282,7 +2437,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) * Returns 0 on success. */ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, + struct device *dev, const struct regulator_init_data *init_data, void *driver_data) { static atomic_t regulator_no = ATOMIC_INIT(0); @@ -2302,6 +2457,22 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (!init_data) return ERR_PTR(-EINVAL); + /* Only one of each should be implemented */ + WARN_ON(regulator_desc->ops->get_voltage && + regulator_desc->ops->get_voltage_sel); + WARN_ON(regulator_desc->ops->set_voltage && + regulator_desc->ops->set_voltage_sel); + + /* If we're using selectors we must implement list_voltage. */ + if (regulator_desc->ops->get_voltage_sel && + !regulator_desc->ops->list_voltage) { + return ERR_PTR(-EINVAL); + } + if (regulator_desc->ops->set_voltage_sel && + !regulator_desc->ops->list_voltage) { + return ERR_PTR(-EINVAL); + } + rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) return ERR_PTR(-ENOMEM); @@ -2399,6 +2570,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, } list_add(&rdev->list, ®ulator_list); + + rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); return rdev; @@ -2431,12 +2604,16 @@ void regulator_unregister(struct regulator_dev *rdev) return; mutex_lock(®ulator_list_mutex); +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(rdev->debugfs); +#endif WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); if (rdev->supply) sysfs_remove_link(&rdev->dev.kobj, "supply"); device_unregister(&rdev->dev); + kfree(rdev->constraints); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); @@ -2465,8 +2642,7 @@ int regulator_suspend_prepare(suspend_state_t state) mutex_unlock(&rdev->mutex); if (ret < 0) { - printk(KERN_ERR "%s: failed to prepare %s\n", - __func__, rdev_get_name(rdev)); + rdev_err(rdev, "failed to prepare\n"); goto out; } } @@ -2572,10 +2748,16 @@ static int __init regulator_init(void) { int ret; - printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); - ret = class_register(®ulator_class); +#ifdef CONFIG_DEBUG_FS + debugfs_root = debugfs_create_dir("regulator", NULL); + if (IS_ERR(debugfs_root) || !debugfs_root) { + pr_warn("regulator: Failed to create debugfs directory\n"); + debugfs_root = NULL; + } +#endif + regulator_dummy_init(); return ret; @@ -2590,7 +2772,6 @@ static int __init regulator_init_complete(void) struct regulator_ops *ops; struct regulation_constraints *c; int enabled, ret; - const char *name; mutex_lock(®ulator_list_mutex); @@ -2602,8 +2783,6 @@ static int __init regulator_init_complete(void) ops = rdev->desc->ops; c = rdev->constraints; - name = rdev_get_name(rdev); - if (!ops->disable || (c && c->always_on)) continue; @@ -2624,13 +2803,10 @@ static int __init regulator_init_complete(void) if (has_full_constraints) { /* We log since this may kill the system if it * goes wrong. */ - printk(KERN_INFO "%s: disabling %s\n", - __func__, name); + rdev_info(rdev, "disabling\n"); ret = ops->disable(rdev); if (ret != 0) { - printk(KERN_ERR - "%s: couldn't disable %s: %d\n", - __func__, name, ret); + rdev_err(rdev, "couldn't disable: %d\n", ret); } } else { /* The intention is that in future we will @@ -2638,9 +2814,7 @@ static int __init regulator_init_complete(void) * so warn even if we aren't going to do * anything here. */ - printk(KERN_WARNING - "%s: incomplete constraints, leaving %s on\n", - __func__, name); + rdev_warn(rdev, "incomplete constraints, leaving on\n"); } unlock: diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index f8c4661a7a81..362e08221085 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -107,7 +107,7 @@ static inline int check_range(struct da903x_regulator_info *info, /* DA9030/DA9034 common operations */ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -119,6 +119,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -187,7 +188,8 @@ static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector) /* DA9030 specific operations */ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); @@ -200,6 +202,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */ @@ -214,7 +217,8 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, } static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); @@ -234,6 +238,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, val = (min_uV - thresh + info->step_uV - 1) / info->step_uV; } + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -263,7 +268,7 @@ static int da9030_get_ldo14_voltage(struct regulator_dev *rdev) /* DA9034 specific operations */ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -276,6 +281,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -289,7 +295,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, } static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -302,6 +308,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val); + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index b8cc6389a541..e4b3592e8176 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -58,7 +58,9 @@ out: return data; } -static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) +static int isl6271a_set_voltage(struct regulator_dev *dev, + int minuV, int maxuV, + unsigned *selector) { struct isl_pmic *pmic = rdev_get_drvdata(dev); int vsel, err, data; @@ -78,6 +80,8 @@ static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) /* Convert the microvolts to data for the chip */ data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP; + *selector = data; + mutex_lock(&pmic->mtx); err = i2c_smbus_write_byte(pmic->client, data); @@ -169,7 +173,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, init_data, pmic); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); - err = PTR_ERR(pmic->rdev); + err = PTR_ERR(pmic->rdev[i]); goto error; } } diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 3bb82b624e19..0f22ef12601c 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -168,7 +168,8 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) } static int lp3971_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3971_LDO1; @@ -187,6 +188,8 @@ static int lp3971_ldo_set_voltage(struct regulator_dev *dev, if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val << LDO_VOL_CONTR_SHIFT(ldo)); @@ -256,7 +259,8 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) } static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3971_DCDC1; @@ -277,6 +281,8 @@ static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), BUCK_TARGET_VOL_MASK, val); if (ret) diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index e07062fd0b42..6aa1b506fb5d 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -292,7 +292,8 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) } static int lp3972_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3972_LDO1; @@ -313,6 +314,8 @@ static int lp3972_ldo_set_voltage(struct regulator_dev *dev, if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), LP3972_LDO_VOL_MASK(ldo) << shift, val << shift); @@ -416,7 +419,8 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) } static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3972_DCDC1; @@ -438,6 +442,8 @@ static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, vol_map[val] > max_vol) return -EINVAL; + *selector = val; + ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), LP3972_BUCK_VOL_MASK, val); if (ret) diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 559cfa271a44..3f49512c5134 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -63,12 +63,12 @@ static int max1586_v3_calc_voltage(struct max1586_data *max1586, return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL); } -static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct max1586_data *max1586 = rdev_get_drvdata(rdev); struct i2c_client *client = max1586->client; unsigned range_uV = max1586->max_uV - max1586->min_uV; - unsigned selector; u8 v3_prog; if (min_uV > max1586->max_uV || max_uV < max1586->min_uV) @@ -76,15 +76,15 @@ static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (min_uV < max1586->min_uV) min_uV = max1586->min_uV; - selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + + *selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + range_uV - 1) / range_uV; - if (max1586_v3_calc_voltage(max1586, selector) > max_uV) + if (max1586_v3_calc_voltage(max1586, *selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", - max1586_v3_calc_voltage(max1586, selector) / 1000); + max1586_v3_calc_voltage(max1586, *selector) / 1000); - v3_prog = I2C_V3_SELECT | (u8) selector; + v3_prog = I2C_V3_SELECT | (u8) *selector; return i2c_smbus_write_byte(client, v3_prog); } @@ -110,10 +110,10 @@ static int max1586_v6_calc_voltage(unsigned selector) return voltages_uv[selector]; } -static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *selector) { struct i2c_client *client = rdev_get_drvdata(rdev); - unsigned selector; u8 v6_prog; if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) @@ -122,21 +122,21 @@ static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) return -EINVAL; if (min_uV < 1800000) - selector = 0; + *selector = 0; else if (min_uV < 2500000) - selector = 1; + *selector = 1; else if (min_uV < 3000000) - selector = 2; + *selector = 2; else if (min_uV >= 3000000) - selector = 3; + *selector = 3; - if (max1586_v6_calc_voltage(selector) > max_uV) + if (max1586_v6_calc_voltage(*selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", - max1586_v6_calc_voltage(selector) / 1000); + max1586_v6_calc_voltage(*selector) / 1000); - v6_prog = I2C_V6_SELECT | (u8) selector; + v6_prog = I2C_V6_SELECT | (u8) *selector; return i2c_smbus_write_byte(client, v6_prog); } diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 6b60a9c0366b..30eb9e54f7ec 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -155,7 +155,7 @@ static int max8649_get_voltage(struct regulator_dev *rdev) } static int max8649_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -168,6 +168,7 @@ static int max8649_set_voltage(struct regulator_dev *rdev, data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1) / MAX8649_DCDC_STEP; mask = MAX8649_VOL_MASK; + *selector = data & mask; return max8649_set_bits(info->i2c, info->vol_reg, mask, data); } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index c570e6eb0db2..33f5d9a492ef 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -141,7 +141,8 @@ static int max8660_dcdc_get(struct regulator_dev *rdev) return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP; } -static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 reg, selector, bits; @@ -154,6 +155,7 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV) selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1)) / MAX8660_DCDC_STEP; + *s = selector; ret = max8660_dcdc_list(rdev, selector); if (ret < 0 || ret > max_uV) @@ -196,7 +198,8 @@ static int max8660_ldo5_get(struct regulator_dev *rdev) return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP; } -static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 selector; @@ -213,6 +216,8 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector); if (ret) return ret; @@ -270,7 +275,8 @@ static int max8660_ldo67_get(struct regulator_dev *rdev) return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP; } -static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 selector; @@ -288,6 +294,8 @@ static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + if (rdev_get_id(rdev) == MAX8660_V6) return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector); else diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 552cad85ae5a..8ae147549c6a 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -55,7 +55,7 @@ static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) } static int max8925_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned int *selector) { struct max8925_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -66,6 +66,7 @@ static int max8925_set_voltage(struct regulator_dev *rdev, return -EINVAL; } data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = data; data <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 0d5dda4fd911..a8f4ecfb0843 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -133,7 +133,7 @@ static int max8952_get_voltage(struct regulator_dev *rdev) } static int max8952_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8952_data *max8952 = rdev_get_drvdata(rdev); s8 vid = -1, i; @@ -156,6 +156,7 @@ static int max8952_set_voltage(struct regulator_dev *rdev, if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) { max8952->vid0 = (vid % 2 == 1); max8952->vid1 = (((vid >> 1) % 2) == 1); + *selector = vid; gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); } else diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 5c20756db607..7568df6122ab 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -304,7 +304,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev) } static int max8998_set_voltage_ldo(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8998->iodev->i2c; @@ -331,6 +331,8 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev, if (desc->min + desc->step*i > max_vol) return -EINVAL; + *selector = i; + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; @@ -352,7 +354,7 @@ static inline void buck2_gpio_set(int gpio, int v) } static int max8998_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct max8998_platform_data *pdata = @@ -384,6 +386,8 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, if (desc->min + desc->step*i > max_vol) return -EINVAL; + *selector = i; + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index ecd99f59dba8..3e5d0c3b4e53 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -1,6 +1,7 @@ /* * Regulator Driver for Freescale MC13783 PMIC * + * Copyright 2010 Yong Shen <yong.shen@linaro.org> * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> * @@ -17,6 +18,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include "mc13xxx.h" #define MC13783_REG_SWITCHERS5 29 #define MC13783_REG_SWITCHERS5_SW3EN (1 << 20) @@ -89,154 +91,106 @@ #define MC13783_REG_POWERMISC_PWGTSPI_M (3 << 15) -struct mc13783_regulator { - struct regulator_desc desc; - int reg; - int enable_bit; - int vsel_reg; - int vsel_shift; - int vsel_mask; - int const *voltages; -}; - /* Voltage Values */ -static const int const mc13783_sw3_val[] = { +static const int mc13783_sw3_val[] = { 5000000, 5000000, 5000000, 5500000, }; -static const int const mc13783_vaudio_val[] = { +static const int mc13783_vaudio_val[] = { 2775000, }; -static const int const mc13783_viohi_val[] = { +static const int mc13783_viohi_val[] = { 2775000, }; -static const int const mc13783_violo_val[] = { +static const int mc13783_violo_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int const mc13783_vdig_val[] = { +static const int mc13783_vdig_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int const mc13783_vgen_val[] = { +static const int mc13783_vgen_val[] = { 1200000, 1300000, 1500000, 1800000, 1100000, 2000000, 2775000, 2400000, }; -static const int const mc13783_vrfdig_val[] = { +static const int mc13783_vrfdig_val[] = { 1200000, 1500000, 1800000, 1875000, }; -static const int const mc13783_vrfref_val[] = { +static const int mc13783_vrfref_val[] = { 2475000, 2600000, 2700000, 2775000, }; -static const int const mc13783_vrfcp_val[] = { +static const int mc13783_vrfcp_val[] = { 2700000, 2775000, }; -static const int const mc13783_vsim_val[] = { +static const int mc13783_vsim_val[] = { 1800000, 2900000, 3000000, }; -static const int const mc13783_vesim_val[] = { +static const int mc13783_vesim_val[] = { 1800000, 2900000, }; -static const int const mc13783_vcam_val[] = { +static const int mc13783_vcam_val[] = { 1500000, 1800000, 2500000, 2550000, 2600000, 2750000, 2800000, 3000000, }; -static const int const mc13783_vrfbg_val[] = { +static const int mc13783_vrfbg_val[] = { 1250000, }; -static const int const mc13783_vvib_val[] = { +static const int mc13783_vvib_val[] = { 1300000, 1800000, 2000000, 3000000, }; -static const int const mc13783_vmmc_val[] = { +static const int mc13783_vmmc_val[] = { 1600000, 1800000, 2000000, 2600000, 2700000, 2800000, 2900000, 3000000, }; -static const int const mc13783_vrf_val[] = { +static const int mc13783_vrf_val[] = { 1500000, 1875000, 2700000, 2775000, }; -static const int const mc13783_gpo_val[] = { +static const int mc13783_gpo_val[] = { 3100000, }; -static const int const mc13783_pwgtdrv_val[] = { +static const int mc13783_pwgtdrv_val[] = { 5500000, }; -static struct regulator_ops mc13783_regulator_ops; -static struct regulator_ops mc13783_fixed_regulator_ops; static struct regulator_ops mc13783_gpo_regulator_ops; -#define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .vsel_reg = MC13783_REG_ ## _vsel_reg, \ - .vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\ - .vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\ - .voltages = _voltages, \ - } +#define MC13783_DEFINE(prefix, name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13783_REG_, name, reg, vsel_reg, voltages, \ + mc13xxx_regulator_ops) -#define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_fixed_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ - } +#define MC13783_FIXED_DEFINE(prefix, name, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13783_REG_, name, reg, voltages, \ + mc13xxx_fixed_regulator_ops) -#define MC13783_GPO_DEFINE(prefix, _name, _reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_gpo_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ - } +#define MC13783_GPO_DEFINE(prefix, name, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13783_REG_, name, reg, voltages, \ + mc13783_gpo_regulator_ops) #define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages) + MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) #define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages) + MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) -static struct mc13783_regulator mc13783_regulators[] = { +static struct mc13xxx_regulator mc13783_regulators[] = { MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), - MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), - MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val), + MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), + MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val), MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \ mc13783_violo_val), MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ @@ -255,7 +209,7 @@ static struct mc13783_regulator mc13783_regulators[] = { mc13783_vesim_val), MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ mc13783_vcam_val), - MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), + MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \ mc13783_vvib_val), MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \ @@ -266,215 +220,24 @@ static struct mc13783_regulator mc13783_regulators[] = { mc13783_vmmc_val), MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \ mc13783_vmmc_val), - MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), - MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), -}; - -struct mc13783_regulator_priv { - struct mc13783 *mc13783; - u32 powermisc_pwgt_state; - struct regulator_dev *regulators[]; -}; - -static int mc13783_regulator_enable(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg, - mc13783_regulators[id].enable_bit, - mc13783_regulators[id].enable_bit); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_disable(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg, - mc13783_regulators[id].enable_bit, 0); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - unsigned int val; - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - return (val & mc13783_regulators[id].enable_bit) != 0; -} - -static int mc13783_regulator_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - int id = rdev_get_id(rdev); - - if (selector >= mc13783_regulators[id].desc.n_voltages) - return -EINVAL; - - return mc13783_regulators[id].voltages[selector]; -} - -static int mc13783_get_best_voltage_index(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int reg_id = rdev_get_id(rdev); - int i; - int bestmatch; - int bestindex; - - /* - * Locate the minimum voltage fitting the criteria on - * this regulator. The switchable voltages are not - * in strict falling order so we need to check them - * all for the best match. - */ - bestmatch = INT_MAX; - bestindex = -1; - for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) { - if (mc13783_regulators[reg_id].voltages[i] >= min_uV && - mc13783_regulators[reg_id].voltages[i] < bestmatch) { - bestmatch = mc13783_regulators[reg_id].voltages[i]; - bestindex = i; - } - } - - if (bestindex < 0 || bestmatch > max_uV) { - dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", - min_uV, max_uV); - return -EINVAL; - } - return bestindex; -} - -static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int value, id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - /* Find the best index */ - value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV); - dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value); - if (value < 0) - return value; - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg, - mc13783_regulators[id].vsel_mask, - value << mc13783_regulators[id].vsel_shift); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_get_voltage(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - unsigned int val; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, - mc13783_regulators[id].vsel_reg, &val); - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - val = (val & mc13783_regulators[id].vsel_mask) - >> mc13783_regulators[id].vsel_shift; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); - - BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages); - - return mc13783_regulators[id].voltages[val]; -} - -static struct regulator_ops mc13783_regulator_ops = { - .enable = mc13783_regulator_enable, - .disable = mc13783_regulator_disable, - .is_enabled = mc13783_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_regulator_set_voltage, - .get_voltage = mc13783_regulator_get_voltage, -}; - -static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int id = rdev_get_id(rdev); - - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - if (min_uV >= mc13783_regulators[id].voltages[0] && - max_uV <= mc13783_regulators[id].voltages[0]) - return 0; - else - return -EINVAL; -} - -static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev) -{ - int id = rdev_get_id(rdev); - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - return mc13783_regulators[id].voltages[0]; -} - -static struct regulator_ops mc13783_fixed_regulator_ops = { - .enable = mc13783_regulator_enable, - .disable = mc13783_regulator_disable, - .is_enabled = mc13783_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_fixed_regulator_set_voltage, - .get_voltage = mc13783_fixed_regulator_get_voltage, + MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO3, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO4, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), }; -static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, - u32 val) +static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) { - struct mc13783 *mc13783 = priv->mc13783; + struct mc13xxx *mc13783 = priv->mc13xxx; int ret; u32 valread; BUG_ON(val & ~mask); - ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); + ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); if (ret) return ret; @@ -489,34 +252,36 @@ static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) | priv->powermisc_pwgt_state; - return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread); + return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread); } static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); int ret; - u32 en_val = mc13783_regulators[id].enable_bit; + u32 en_val = mc13xxx_regulators[id].enable_bit; dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); /* Power Gate enable value is 0 */ - if (id == MC13783_REGU_PWGT1SPI || - id == MC13783_REGU_PWGT2SPI) + if (id == MC13783_REG_PWGT1SPI || + id == MC13783_REG_PWGT2SPI) en_val = 0; - mc13783_lock(priv->mc13783); - ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, + mc13xxx_lock(priv->mc13xxx); + ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, en_val); - mc13783_unlock(priv->mc13783); + mc13xxx_unlock(priv->mc13xxx); return ret; } static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); int ret; u32 dis_val = 0; @@ -524,27 +289,28 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); /* Power Gate disable value is 1 */ - if (id == MC13783_REGU_PWGT1SPI || - id == MC13783_REGU_PWGT2SPI) - dis_val = mc13783_regulators[id].enable_bit; + if (id == MC13783_REG_PWGT1SPI || + id == MC13783_REG_PWGT2SPI) + dis_val = mc13xxx_regulators[id].enable_bit; - mc13783_lock(priv->mc13783); - ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, + mc13xxx_lock(priv->mc13xxx); + ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, dis_val); - mc13783_unlock(priv->mc13783); + mc13xxx_unlock(priv->mc13xxx); return ret; } static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int ret, id = rdev_get_id(rdev); unsigned int val; - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); - mc13783_unlock(priv->mc13783); + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); if (ret) return ret; @@ -554,22 +320,22 @@ static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) | (priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M); - return (val & mc13783_regulators[id].enable_bit) != 0; + return (val & mc13xxx_regulators[id].enable_bit) != 0; } static struct regulator_ops mc13783_gpo_regulator_ops = { .enable = mc13783_gpo_regulator_enable, .disable = mc13783_gpo_regulator_disable, .is_enabled = mc13783_gpo_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_fixed_regulator_set_voltage, - .get_voltage = mc13783_fixed_regulator_get_voltage, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; static int __devinit mc13783_regulator_probe(struct platform_device *pdev) { - struct mc13783_regulator_priv *priv; - struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_regulator_priv *priv; + struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); struct mc13783_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783_regulator_init_data *init_data; @@ -583,7 +349,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->mc13783 = mc13783; + priv->mc13xxx_regulators = mc13783_regulators; + priv->mc13xxx = mc13783; for (i = 0; i < pdata->num_regulators; i++) { init_data = &pdata->regulators[i]; @@ -613,7 +380,7 @@ err: static int __devexit mc13783_regulator_remove(struct platform_device *pdev) { - struct mc13783_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13783_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); int i; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c new file mode 100644 index 000000000000..1b8f7398a4a8 --- /dev/null +++ b/drivers/regulator/mc13892-regulator.c @@ -0,0 +1,635 @@ +/* + * Regulator Driver for Freescale MC13892 PMIC + * + * Copyright 2010 Yong Shen <yong.shen@linaro.org> + * + * Based on draft driver from Arnaud Patard <arnaud.patard@rtp-net.org> + * + * 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/mfd/mc13892.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/err.h> +#include "mc13xxx.h" + +#define MC13892_REVISION 7 + +#define MC13892_POWERCTL0 13 +#define MC13892_POWERCTL0_USEROFFSPI 3 +#define MC13892_POWERCTL0_VCOINCELLVSEL 20 +#define MC13892_POWERCTL0_VCOINCELLVSEL_M (7<<20) +#define MC13892_POWERCTL0_VCOINCELLEN (1<<23) + +#define MC13892_SWITCHERS0_SWxHI (1<<23) + +#define MC13892_SWITCHERS0 24 +#define MC13892_SWITCHERS0_SW1VSEL 0 +#define MC13892_SWITCHERS0_SW1VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS0_SW1HI (1<<23) +#define MC13892_SWITCHERS0_SW1EN 0 + +#define MC13892_SWITCHERS1 25 +#define MC13892_SWITCHERS1_SW2VSEL 0 +#define MC13892_SWITCHERS1_SW2VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS1_SW2HI (1<<23) +#define MC13892_SWITCHERS1_SW2EN 0 + +#define MC13892_SWITCHERS2 26 +#define MC13892_SWITCHERS2_SW3VSEL 0 +#define MC13892_SWITCHERS2_SW3VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS2_SW3HI (1<<23) +#define MC13892_SWITCHERS2_SW3EN 0 + +#define MC13892_SWITCHERS3 27 +#define MC13892_SWITCHERS3_SW4VSEL 0 +#define MC13892_SWITCHERS3_SW4VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS3_SW4HI (1<<23) +#define MC13892_SWITCHERS3_SW4EN 0 + +#define MC13892_SWITCHERS4 28 +#define MC13892_SWITCHERS4_SW1MODE 0 +#define MC13892_SWITCHERS4_SW1MODE_AUTO (8<<0) +#define MC13892_SWITCHERS4_SW1MODE_M (0xf<<0) +#define MC13892_SWITCHERS4_SW2MODE 10 +#define MC13892_SWITCHERS4_SW2MODE_AUTO (8<<10) +#define MC13892_SWITCHERS4_SW2MODE_M (0xf<<10) + +#define MC13892_SWITCHERS5 29 +#define MC13892_SWITCHERS5_SW3MODE 0 +#define MC13892_SWITCHERS5_SW3MODE_AUTO (8<<0) +#define MC13892_SWITCHERS5_SW3MODE_M (0xf<<0) +#define MC13892_SWITCHERS5_SW4MODE 8 +#define MC13892_SWITCHERS5_SW4MODE_AUTO (8<<8) +#define MC13892_SWITCHERS5_SW4MODE_M (0xf<<8) +#define MC13892_SWITCHERS5_SWBSTEN (1<<20) + +#define MC13892_REGULATORSETTING0 30 +#define MC13892_REGULATORSETTING0_VGEN1VSEL 0 +#define MC13892_REGULATORSETTING0_VDIGVSEL 4 +#define MC13892_REGULATORSETTING0_VGEN2VSEL 6 +#define MC13892_REGULATORSETTING0_VPLLVSEL 9 +#define MC13892_REGULATORSETTING0_VUSB2VSEL 11 +#define MC13892_REGULATORSETTING0_VGEN3VSEL 14 +#define MC13892_REGULATORSETTING0_VCAMVSEL 16 + +#define MC13892_REGULATORSETTING0_VGEN1VSEL_M (3<<0) +#define MC13892_REGULATORSETTING0_VDIGVSEL_M (3<<4) +#define MC13892_REGULATORSETTING0_VGEN2VSEL_M (7<<6) +#define MC13892_REGULATORSETTING0_VPLLVSEL_M (3<<9) +#define MC13892_REGULATORSETTING0_VUSB2VSEL_M (3<<11) +#define MC13892_REGULATORSETTING0_VGEN3VSEL_M (1<<14) +#define MC13892_REGULATORSETTING0_VCAMVSEL_M (3<<16) + +#define MC13892_REGULATORSETTING1 31 +#define MC13892_REGULATORSETTING1_VVIDEOVSEL 2 +#define MC13892_REGULATORSETTING1_VAUDIOVSEL 4 +#define MC13892_REGULATORSETTING1_VSDVSEL 6 + +#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M (3<<2) +#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M (3<<4) +#define MC13892_REGULATORSETTING1_VSDVSEL_M (7<<6) + +#define MC13892_REGULATORMODE0 32 +#define MC13892_REGULATORMODE0_VGEN1EN (1<<0) +#define MC13892_REGULATORMODE0_VGEN1STDBY (1<<1) +#define MC13892_REGULATORMODE0_VGEN1MODE (1<<2) +#define MC13892_REGULATORMODE0_VIOHIEN (1<<3) +#define MC13892_REGULATORMODE0_VIOHISTDBY (1<<4) +#define MC13892_REGULATORMODE0_VIOHIMODE (1<<5) +#define MC13892_REGULATORMODE0_VDIGEN (1<<9) +#define MC13892_REGULATORMODE0_VDIGSTDBY (1<<10) +#define MC13892_REGULATORMODE0_VDIGMODE (1<<11) +#define MC13892_REGULATORMODE0_VGEN2EN (1<<12) +#define MC13892_REGULATORMODE0_VGEN2STDBY (1<<13) +#define MC13892_REGULATORMODE0_VGEN2MODE (1<<14) +#define MC13892_REGULATORMODE0_VPLLEN (1<<15) +#define MC13892_REGULATORMODE0_VPLLSTDBY (1<<16) +#define MC13892_REGULATORMODE0_VPLLMODE (1<<17) +#define MC13892_REGULATORMODE0_VUSB2EN (1<<18) +#define MC13892_REGULATORMODE0_VUSB2STDBY (1<<19) +#define MC13892_REGULATORMODE0_VUSB2MODE (1<<20) + +#define MC13892_REGULATORMODE1 33 +#define MC13892_REGULATORMODE1_VGEN3EN (1<<0) +#define MC13892_REGULATORMODE1_VGEN3STDBY (1<<1) +#define MC13892_REGULATORMODE1_VGEN3MODE (1<<2) +#define MC13892_REGULATORMODE1_VCAMEN (1<<6) +#define MC13892_REGULATORMODE1_VCAMSTDBY (1<<7) +#define MC13892_REGULATORMODE1_VCAMMODE (1<<8) +#define MC13892_REGULATORMODE1_VCAMCONFIGEN (1<<9) +#define MC13892_REGULATORMODE1_VVIDEOEN (1<<12) +#define MC13892_REGULATORMODE1_VVIDEOSTDBY (1<<13) +#define MC13892_REGULATORMODE1_VVIDEOMODE (1<<14) +#define MC13892_REGULATORMODE1_VAUDIOEN (1<<15) +#define MC13892_REGULATORMODE1_VAUDIOSTDBY (1<<16) +#define MC13892_REGULATORMODE1_VAUDIOMODE (1<<17) +#define MC13892_REGULATORMODE1_VSDEN (1<<18) +#define MC13892_REGULATORMODE1_VSDSTDBY (1<<19) +#define MC13892_REGULATORMODE1_VSDMODE (1<<20) + +#define MC13892_POWERMISC 34 +#define MC13892_POWERMISC_GPO1EN (1<<6) +#define MC13892_POWERMISC_GPO2EN (1<<8) +#define MC13892_POWERMISC_GPO3EN (1<<10) +#define MC13892_POWERMISC_GPO4EN (1<<12) +#define MC13892_POWERMISC_PWGT1SPIEN (1<<15) +#define MC13892_POWERMISC_PWGT2SPIEN (1<<16) +#define MC13892_POWERMISC_GPO4ADINEN (1<<21) + +#define MC13892_POWERMISC_PWGTSPI_M (3 << 15) + +#define MC13892_USB1 50 +#define MC13892_USB1_VUSBEN (1<<3) + +static const int mc13892_vcoincell[] = { + 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, + 3200000, 3300000, +}; + +static const int mc13892_sw1[] = { + 600000, 625000, 650000, 675000, 700000, 725000, + 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, + 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, + 1350000, 1375000 +}; + +static const int mc13892_sw[] = { + 600000, 625000, 650000, 675000, 700000, 725000, + 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, + 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, + 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1575000, 1600000, 1625000, + 1650000, 1675000, 1700000, 1725000, 1750000, 1775000, + 1800000, 1825000, 1850000, 1875000 +}; + +static const int mc13892_swbst[] = { + 5000000, +}; + +static const int mc13892_viohi[] = { + 2775000, +}; + +static const int mc13892_vpll[] = { + 1050000, 1250000, 1650000, 1800000, +}; + +static const int mc13892_vdig[] = { + 1050000, 1250000, 1650000, 1800000, +}; + +static const int mc13892_vsd[] = { + 1800000, 2000000, 2600000, 2700000, + 2800000, 2900000, 3000000, 3150000, +}; + +static const int mc13892_vusb2[] = { + 2400000, 2600000, 2700000, 2775000, +}; + +static const int mc13892_vvideo[] = { + 2700000, 2775000, 2500000, 2600000, +}; + +static const int mc13892_vaudio[] = { + 2300000, 2500000, 2775000, 3000000, +}; + +static const int mc13892_vcam[] = { + 2500000, 2600000, 2750000, 3000000, +}; + +static const int mc13892_vgen1[] = { + 1200000, 1500000, 2775000, 3150000, +}; + +static const int mc13892_vgen2[] = { + 1200000, 1500000, 1600000, 1800000, + 2700000, 2800000, 3000000, 3150000, +}; + +static const int mc13892_vgen3[] = { + 1800000, 2900000, +}; + +static const int mc13892_vusb[] = { + 3300000, +}; + +static const int mc13892_gpo[] = { + 2750000, +}; + +static const int mc13892_pwgtdrv[] = { + 5000000, +}; + +static struct regulator_ops mc13892_gpo_regulator_ops; +/* sw regulators need special care due to the "hi bit" */ +static struct regulator_ops mc13892_sw_regulator_ops; + + +#define MC13892_FIXED_DEFINE(name, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \ + mc13xxx_fixed_regulator_ops) + +#define MC13892_GPO_DEFINE(name, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \ + mc13892_gpo_regulator_ops) + +#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ + mc13892_sw_regulator_ops) + +#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ + mc13xxx_regulator_ops) + +static struct mc13xxx_regulator mc13892_regulators[] = { + MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell), + MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1), + MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw), + MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw), + MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw), + MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst), + MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi), + MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vpll), + MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vdig), + MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vsd), + MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vusb2), + MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vvideo), + MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vaudio), + MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ + mc13892_vcam), + MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vgen1), + MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vgen2), + MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, \ + mc13892_vgen3), + MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb), + MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv), + MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), +}; + +static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) +{ + struct mc13xxx *mc13892 = priv->mc13xxx; + int ret; + u32 valread; + + BUG_ON(val & ~mask); + + ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread); + if (ret) + return ret; + + /* Update the stored state for Power Gates. */ + priv->powermisc_pwgt_state = + (priv->powermisc_pwgt_state & ~mask) | val; + priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M; + + /* Construct the new register value */ + valread = (valread & ~mask) | val; + /* Overwrite the PWGTxEN with the stored version */ + valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) | + priv->powermisc_pwgt_state; + + return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread); +} + +static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + u32 en_val = mc13892_regulators[id].enable_bit; + u32 mask = mc13892_regulators[id].enable_bit; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + /* Power Gate enable value is 0 */ + if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) + en_val = 0; + + if (id == MC13892_GPO4) + mask |= MC13892_POWERMISC_GPO4ADINEN; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13892_powermisc_rmw(priv, mask, en_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + u32 dis_val = 0; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + /* Power Gate disable value is 1 */ + if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) + dis_val = mc13892_regulators[id].enable_bit; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit, + dis_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + /* Power Gates state is stored in powermisc_pwgt_state + * where the meaning of bits is negated */ + val = (val & ~MC13892_POWERMISC_PWGTSPI_M) | + (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M); + + return (val & mc13892_regulators[id].enable_bit) != 0; +} + + +static struct regulator_ops mc13892_gpo_regulator_ops = { + .enable = mc13892_gpo_regulator_enable, + .disable = mc13892_gpo_regulator_disable, + .is_enabled = mc13892_gpo_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, +}; + +static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val, hi; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13892_regulators[id].vsel_reg, &val); + mc13xxx_unlock(priv->mc13xxx); + if (ret) + return ret; + + hi = val & MC13892_SWITCHERS0_SWxHI; + val = (val & mc13892_regulators[id].vsel_mask) + >> mc13892_regulators[id].vsel_shift; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + + if (hi) + val = (25000 * val) + 1100000; + else + val = (25000 * val) + 600000; + + return val; +} + +static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int hi, value, val, mask, id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + /* Find the best index */ + value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); + dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); + if (value < 0) + return value; + + value = mc13892_regulators[id].voltages[value]; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13892_regulators[id].vsel_reg, &val); + if (ret) + goto err; + + hi = val & MC13892_SWITCHERS0_SWxHI; + if (value > 1375) + hi = 1; + if (value < 1100) + hi = 0; + + if (hi) { + value = (value - 1100000) / 25000; + value |= MC13892_SWITCHERS0_SWxHI; + } else + value = (value - 600000) / 25000; + + mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI; + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, + mask, value << mc13892_regulators[id].vsel_shift); +err: + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static struct regulator_ops mc13892_sw_regulator_ops = { + .is_enabled = mc13xxx_sw_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13892_sw_regulator_set_voltage, + .get_voltage = mc13892_sw_regulator_get_voltage, +}; + +static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + unsigned int en_val = 0; + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + + if (mode == REGULATOR_MODE_FAST) + en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, + MC13892_REGULATORMODE1_VCAMCONFIGEN, en_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + + +static int __devinit mc13892_regulator_probe(struct platform_device *pdev) +{ + struct mc13xxx_regulator_priv *priv; + struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); + struct mc13xxx_regulator_init_data *init_data; + int i, ret; + u32 val; + + priv = kzalloc(sizeof(*priv) + + pdata->num_regulators * sizeof(priv->regulators[0]), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->mc13xxx_regulators = mc13892_regulators; + priv->mc13xxx = mc13892; + + mc13xxx_lock(mc13892); + ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val); + if (ret) + goto err_free; + + /* enable switch auto mode */ + if ((val & 0x0000FFFF) == 0x45d0) { + ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4, + MC13892_SWITCHERS4_SW1MODE_M | + MC13892_SWITCHERS4_SW2MODE_M, + MC13892_SWITCHERS4_SW1MODE_AUTO | + MC13892_SWITCHERS4_SW2MODE_AUTO); + if (ret) + goto err_free; + + ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, + MC13892_SWITCHERS5_SW3MODE_M | + MC13892_SWITCHERS5_SW4MODE_M, + MC13892_SWITCHERS5_SW3MODE_AUTO | + MC13892_SWITCHERS5_SW4MODE_AUTO); + if (ret) + goto err_free; + } + mc13xxx_unlock(mc13892); + + mc13892_regulators[MC13892_VCAM].desc.ops->set_mode + = mc13892_vcam_set_mode; + mc13892_regulators[MC13892_VCAM].desc.ops->get_mode + = mc13892_vcam_get_mode; + for (i = 0; i < pdata->num_regulators; i++) { + init_data = &pdata->regulators[i]; + priv->regulators[i] = regulator_register( + &mc13892_regulators[init_data->id].desc, + &pdev->dev, init_data->init_data, priv); + + if (IS_ERR(priv->regulators[i])) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + mc13892_regulators[i].desc.name); + ret = PTR_ERR(priv->regulators[i]); + goto err; + } + } + + platform_set_drvdata(pdev, priv); + + return 0; +err: + while (--i >= 0) + regulator_unregister(priv->regulators[i]); + +err_free: + mc13xxx_unlock(mc13892); + kfree(priv); + + return ret; +} + +static int __devexit mc13892_regulator_remove(struct platform_device *pdev) +{ + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); + int i; + + platform_set_drvdata(pdev, NULL); + + for (i = 0; i < pdata->num_regulators; i++) + regulator_unregister(priv->regulators[i]); + + kfree(priv); + return 0; +} + +static struct platform_driver mc13892_regulator_driver = { + .driver = { + .name = "mc13892-regulator", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(mc13892_regulator_remove), + .probe = mc13892_regulator_probe, +}; + +static int __init mc13892_regulator_init(void) +{ + return platform_driver_register(&mc13892_regulator_driver); +} +subsys_initcall(mc13892_regulator_init); + +static void __exit mc13892_regulator_exit(void) +{ + platform_driver_unregister(&mc13892_regulator_driver); +} +module_exit(mc13892_regulator_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>"); +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC"); +MODULE_ALIAS("platform:mc13892-regulator"); diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c new file mode 100644 index 000000000000..f53d31b950d4 --- /dev/null +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -0,0 +1,241 @@ +/* + * Regulator Driver for Freescale MC13xxx PMIC + * + * Copyright 2010 Yong Shen <yong.shen@linaro.org> + * + * Based on mc13783 regulator driver : + * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> + * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.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. + * + * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file + * from freescale + */ + +#include <linux/mfd/mc13xxx.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/driver.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/err.h> +#include "mc13xxx.h" + +static int mc13xxx_regulator_enable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, + mc13xxx_regulators[id].enable_bit); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_disable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, 0); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + return (val & mc13xxx_regulators[id].enable_bit) != 0; +} + +int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + int id = rdev_get_id(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + + if (selector >= mc13xxx_regulators[id].desc.n_voltages) + return -EINVAL; + + return mc13xxx_regulators[id].voltages[selector]; +} +EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage); + +int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int reg_id = rdev_get_id(rdev); + int i; + int bestmatch; + int bestindex; + + /* + * Locate the minimum voltage fitting the criteria on + * this regulator. The switchable voltages are not + * in strict falling order so we need to check them + * all for the best match. + */ + bestmatch = INT_MAX; + bestindex = -1; + for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) { + if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV && + mc13xxx_regulators[reg_id].voltages[i] < bestmatch) { + bestmatch = mc13xxx_regulators[reg_id].voltages[i]; + bestindex = i; + } + } + + if (bestindex < 0 || bestmatch > max_uV) { + dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", + min_uV, max_uV); + return -EINVAL; + } + return bestindex; +} +EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index); + +static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int value, id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + /* Find the best index */ + value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); + dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); + if (value < 0) + return value; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, + mc13xxx_regulators[id].vsel_mask, + value << mc13xxx_regulators[id].vsel_shift); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int ret, id = rdev_get_id(rdev); + unsigned int val; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13xxx_regulators[id].vsel_reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + val = (val & mc13xxx_regulators[id].vsel_mask) + >> mc13xxx_regulators[id].vsel_shift; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + + BUG_ON(val < 0 || val > mc13xxx_regulators[id].desc.n_voltages); + + return mc13xxx_regulators[id].voltages[val]; +} + +struct regulator_ops mc13xxx_regulator_ops = { + .enable = mc13xxx_regulator_enable, + .disable = mc13xxx_regulator_disable, + .is_enabled = mc13xxx_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_regulator_set_voltage, + .get_voltage = mc13xxx_regulator_get_voltage, +}; +EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops); + +int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + if (min_uV >= mc13xxx_regulators[id].voltages[0] && + max_uV <= mc13xxx_regulators[id].voltages[0]) + return 0; + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); + +int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + return mc13xxx_regulators[id].voltages[0]; +} +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage); + +struct regulator_ops mc13xxx_fixed_regulator_ops = { + .enable = mc13xxx_regulator_enable, + .disable = mc13xxx_regulator_disable, + .is_enabled = mc13xxx_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, +}; +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); + +int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) +{ + return 1; +} +EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>"); +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC"); +MODULE_ALIAS("mc13xxx-regulator-core"); diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h new file mode 100644 index 000000000000..27758267e122 --- /dev/null +++ b/drivers/regulator/mc13xxx.h @@ -0,0 +1,101 @@ +/* + * mc13xxx.h - regulators for the Freescale mc13xxx PMIC + * + * Copyright (C) 2010 Yong Shen <yong.shen@linaro.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. + */ + +#ifndef __LINUX_REGULATOR_MC13XXX_H +#define __LINUX_REGULATOR_MC13XXX_H + +#include <linux/regulator/driver.h> + +struct mc13xxx_regulator { + struct regulator_desc desc; + int reg; + int enable_bit; + int vsel_reg; + int vsel_shift; + int vsel_mask; + int hi_bit; + int const *voltages; +}; + +struct mc13xxx_regulator_priv { + struct mc13xxx *mc13xxx; + u32 powermisc_pwgt_state; + struct mc13xxx_regulator *mc13xxx_regulators; + struct regulator_dev *regulators[]; +}; + +extern int mc13xxx_sw_regulator(struct regulator_dev *rdev); +extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev); +extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, + int min_uV, int max_uV); +extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector); +extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector); +extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev); + +extern struct regulator_ops mc13xxx_regulator_ops; +extern struct regulator_ops mc13xxx_fixed_regulator_ops; + +#define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .vsel_reg = prefix ## _vsel_reg, \ + .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\ + .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\ + .voltages = _voltages, \ + } + +#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .voltages = _voltages, \ + } + +#define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .voltages = _voltages, \ + } + +#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(SW, _name, _reg, _vsel_reg, _voltages, ops) +#define MC13xxx_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages, ops) + +#endif diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 29d0566379ae..31f6e11a7f16 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -151,7 +151,8 @@ static struct pcap_regulator vreg_table[] = { }; static int pcap_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); @@ -170,10 +171,12 @@ static int pcap_regulator_set_voltage(struct regulator_dev *rdev, i = 0; uV = vreg->voltage_table[i] * 1000; - if (min_uV <= uV && uV <= max_uV) + if (min_uV <= uV && uV <= max_uV) { + *selector = i; return ezx_pcap_set_bits(pcap, vreg->reg, (vreg->n_voltages - 1) << vreg->index, i << vreg->index); + } if (i == 0 && rdev_get_id(rdev) == V1) i = vreg->n_voltages - 1; diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index c8f41dc05b76..69a11d9dd87f 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -108,7 +108,8 @@ static unsigned int ldo_voltage_value(u8 bits) } static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct pcf50633 *pcf; int regulator_id, millivolts; @@ -147,6 +148,8 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, return -EINVAL; } + *selector = volt_bits; + return pcf50633_reg_write(pcf, regnr, volt_bits); } diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index cd6d4fc9d74f..60a7ca5409e9 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -321,7 +321,8 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) } static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int dcdc = rdev_get_id(dev); @@ -346,6 +347,8 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, break; } + *selector = vsel; + /* write to the register in case we found a match */ if (vsel == tps->info[dcdc]->table_len) return -EINVAL; @@ -371,7 +374,7 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev) } static int tps65023_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); @@ -396,6 +399,8 @@ static int tps65023_ldo_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[ldo]->table_len) return -EINVAL; + *selector = vsel; + data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); if (data < 0) return data; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 020f5878d7ff..064755290599 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -369,7 +369,8 @@ static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev) } static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, vsel, dcdc = rdev_get_id(dev); @@ -415,6 +416,8 @@ static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[dcdc]->table_len) return -EINVAL; + *selector = vsel; + data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; @@ -450,7 +453,8 @@ static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev) } static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); @@ -483,6 +487,8 @@ static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[ldo]->table_len) return -EINVAL; + *selector = vsel; + data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c new file mode 100644 index 000000000000..176a6be5a8ce --- /dev/null +++ b/drivers/regulator/tps6524x-regulator.c @@ -0,0 +1,693 @@ +/* + * Regulator driver for TPS6524x PMIC + * + * Copyright (C) 2010 Texas Instruments + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#define REG_LDO_SET 0x0 +#define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */ +#define LDO_VSEL_MASK 0x0f +#define LDO2_ILIM_SHIFT 12 +#define LDO2_VSEL_SHIFT 4 +#define LDO1_ILIM_SHIFT 8 +#define LDO1_VSEL_SHIFT 0 + +#define REG_BLOCK_EN 0x1 +#define BLOCK_MASK 1 +#define BLOCK_LDO1_SHIFT 0 +#define BLOCK_LDO2_SHIFT 1 +#define BLOCK_LCD_SHIFT 2 +#define BLOCK_USB_SHIFT 3 + +#define REG_DCDC_SET 0x2 +#define DCDC_VDCDC_MASK 0x1f +#define DCDC_VDCDC1_SHIFT 0 +#define DCDC_VDCDC2_SHIFT 5 +#define DCDC_VDCDC3_SHIFT 10 + +#define REG_DCDC_EN 0x3 +#define DCDCDCDC_EN_MASK 0x1 +#define DCDCDCDC1_EN_SHIFT 0 +#define DCDCDCDC1_PG_MSK BIT(1) +#define DCDCDCDC2_EN_SHIFT 2 +#define DCDCDCDC2_PG_MSK BIT(3) +#define DCDCDCDC3_EN_SHIFT 4 +#define DCDCDCDC3_PG_MSK BIT(5) + +#define REG_USB 0x4 +#define USB_ILIM_SHIFT 0 +#define USB_ILIM_MASK 0x3 +#define USB_TSD_SHIFT 2 +#define USB_TSD_MASK 0x3 +#define USB_TWARN_SHIFT 4 +#define USB_TWARN_MASK 0x3 +#define USB_IWARN_SD BIT(6) +#define USB_FAST_LOOP BIT(7) + +#define REG_ALARM 0x5 +#define ALARM_LDO1 BIT(0) +#define ALARM_DCDC1 BIT(1) +#define ALARM_DCDC2 BIT(2) +#define ALARM_DCDC3 BIT(3) +#define ALARM_LDO2 BIT(4) +#define ALARM_USB_WARN BIT(5) +#define ALARM_USB_ALARM BIT(6) +#define ALARM_LCD BIT(9) +#define ALARM_TEMP_WARM BIT(10) +#define ALARM_TEMP_HOT BIT(11) +#define ALARM_NRST BIT(14) +#define ALARM_POWERUP BIT(15) + +#define REG_INT_ENABLE 0x6 +#define INT_LDO1 BIT(0) +#define INT_DCDC1 BIT(1) +#define INT_DCDC2 BIT(2) +#define INT_DCDC3 BIT(3) +#define INT_LDO2 BIT(4) +#define INT_USB_WARN BIT(5) +#define INT_USB_ALARM BIT(6) +#define INT_LCD BIT(9) +#define INT_TEMP_WARM BIT(10) +#define INT_TEMP_HOT BIT(11) +#define INT_GLOBAL_EN BIT(15) + +#define REG_INT_STATUS 0x7 +#define STATUS_LDO1 BIT(0) +#define STATUS_DCDC1 BIT(1) +#define STATUS_DCDC2 BIT(2) +#define STATUS_DCDC3 BIT(3) +#define STATUS_LDO2 BIT(4) +#define STATUS_USB_WARN BIT(5) +#define STATUS_USB_ALARM BIT(6) +#define STATUS_LCD BIT(9) +#define STATUS_TEMP_WARM BIT(10) +#define STATUS_TEMP_HOT BIT(11) + +#define REG_SOFTWARE_RESET 0xb +#define REG_WRITE_ENABLE 0xd +#define REG_REV_ID 0xf + +#define N_DCDC 3 +#define N_LDO 2 +#define N_SWITCH 2 +#define N_REGULATORS (3 /* DCDC */ + \ + 2 /* LDO */ + \ + 2 /* switch */) + +#define FIXED_ILIMSEL BIT(0) +#define FIXED_VOLTAGE BIT(1) + +#define CMD_READ(reg) ((reg) << 6) +#define CMD_WRITE(reg) (BIT(5) | (reg) << 6) +#define STAT_CLK BIT(3) +#define STAT_WRITE BIT(2) +#define STAT_INVALID BIT(1) +#define STAT_WP BIT(0) + +struct field { + int reg; + int shift; + int mask; +}; + +struct supply_info { + const char *name; + int n_voltages; + const int *voltages; + int fixed_voltage; + int n_ilimsels; + const int *ilimsels; + int fixed_ilimsel; + int flags; + struct field enable, voltage, ilimsel; +}; + +struct tps6524x { + struct device *dev; + struct spi_device *spi; + struct mutex lock; + struct regulator_desc desc[N_REGULATORS]; + struct regulator_dev *rdev[N_REGULATORS]; +}; + +static int __read_reg(struct tps6524x *hw, int reg) +{ + int error = 0; + u16 cmd = CMD_READ(reg), in; + u8 status; + struct spi_message m; + struct spi_transfer t[3]; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 2; + t[0].bits_per_word = 12; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = ∈ + t[1].len = 2; + t[1].bits_per_word = 16; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = &status; + t[2].len = 1; + t[2].bits_per_word = 4; + spi_message_add_tail(&t[2], &m); + + error = spi_sync(hw->spi, &m); + if (error < 0) + return error; + + dev_dbg(hw->dev, "read reg %d, data %x, status %x\n", + reg, in, status); + + if (!(status & STAT_CLK) || (status & STAT_WRITE)) + return -EIO; + + if (status & STAT_INVALID) + return -EINVAL; + + return in; +} + +static int read_reg(struct tps6524x *hw, int reg) +{ + int ret; + + mutex_lock(&hw->lock); + ret = __read_reg(hw, reg); + mutex_unlock(&hw->lock); + + return ret; +} + +static int __write_reg(struct tps6524x *hw, int reg, int val) +{ + int error = 0; + u16 cmd = CMD_WRITE(reg), out = val; + u8 status; + struct spi_message m; + struct spi_transfer t[3]; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 2; + t[0].bits_per_word = 12; + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = &out; + t[1].len = 2; + t[1].bits_per_word = 16; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = &status; + t[2].len = 1; + t[2].bits_per_word = 4; + spi_message_add_tail(&t[2], &m); + + error = spi_sync(hw->spi, &m); + if (error < 0) + return error; + + dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n", + reg, out, status); + + if (!(status & STAT_CLK) || !(status & STAT_WRITE)) + return -EIO; + + if (status & (STAT_INVALID | STAT_WP)) + return -EINVAL; + + return error; +} + +static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val) +{ + int ret; + + ret = __read_reg(hw, reg); + if (ret < 0) + return ret; + + ret &= ~mask; + ret |= val; + + ret = __write_reg(hw, reg, ret); + + return (ret < 0) ? ret : 0; +} + +static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val) +{ + int ret; + + mutex_lock(&hw->lock); + + ret = __write_reg(hw, REG_WRITE_ENABLE, 1); + if (ret) { + dev_err(hw->dev, "failed to set write enable\n"); + goto error; + } + + ret = __rmw_reg(hw, reg, mask, val); + if (ret) + dev_err(hw->dev, "failed to rmw register %d\n", reg); + + ret = __write_reg(hw, REG_WRITE_ENABLE, 0); + if (ret) { + dev_err(hw->dev, "failed to clear write enable\n"); + goto error; + } + +error: + mutex_unlock(&hw->lock); + + return ret; +} + +static int read_field(struct tps6524x *hw, const struct field *field) +{ + int tmp; + + tmp = read_reg(hw, field->reg); + if (tmp < 0) + return tmp; + + return (tmp >> field->shift) & field->mask; +} + +static int write_field(struct tps6524x *hw, const struct field *field, + int val) +{ + if (val & ~field->mask) + return -EOVERFLOW; + + return rmw_protect(hw, field->reg, + field->mask << field->shift, + val << field->shift); +} + +static const int dcdc1_voltages[] = { + 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, + 1000000, 1025000, 1050000, 1075000, + 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, + 1300000, 1325000, 1350000, 1375000, + 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1575000, +}; + +static const int dcdc2_voltages[] = { + 1400000, 1450000, 1500000, 1550000, + 1600000, 1650000, 1700000, 1750000, + 1800000, 1850000, 1900000, 1950000, + 2000000, 2050000, 2100000, 2150000, + 2200000, 2250000, 2300000, 2350000, + 2400000, 2450000, 2500000, 2550000, + 2600000, 2650000, 2700000, 2750000, + 2800000, 2850000, 2900000, 2950000, +}; + +static const int dcdc3_voltages[] = { + 2400000, 2450000, 2500000, 2550000, 2600000, + 2650000, 2700000, 2750000, 2800000, 2850000, + 2900000, 2950000, 3000000, 3050000, 3100000, + 3150000, 3200000, 3250000, 3300000, 3350000, + 3400000, 3450000, 3500000, 3550000, 3600000, +}; + +static const int ldo1_voltages[] = { + 4300000, 4350000, 4400000, 4450000, + 4500000, 4550000, 4600000, 4650000, + 4700000, 4750000, 4800000, 4850000, + 4900000, 4950000, 5000000, 5050000, +}; + +static const int ldo2_voltages[] = { + 1100000, 1150000, 1200000, 1250000, + 1300000, 1700000, 1750000, 1800000, + 1850000, 1900000, 3150000, 3200000, + 3250000, 3300000, 3350000, 3400000, +}; + +static const int ldo_ilimsel[] = { + 400000, 1500000 +}; + +static const int usb_ilimsel[] = { + 200000, 400000, 800000, 1000000 +}; + +#define __MK_FIELD(_reg, _mask, _shift) \ + { .reg = (_reg), .mask = (_mask), .shift = (_shift), } + +static const struct supply_info supply_info[N_REGULATORS] = { + { + .name = "DCDC1", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc1_voltages), + .voltages = dcdc1_voltages, + .fixed_ilimsel = 2400000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC1_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC1_SHIFT), + }, + { + .name = "DCDC2", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc2_voltages), + .voltages = dcdc2_voltages, + .fixed_ilimsel = 1200000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC2_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC2_SHIFT), + }, + { + .name = "DCDC3", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc3_voltages), + .voltages = dcdc3_voltages, + .fixed_ilimsel = 1200000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC3_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC3_SHIFT), + }, + { + .name = "LDO1", + .n_voltages = ARRAY_SIZE(ldo1_voltages), + .voltages = ldo1_voltages, + .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), + .ilimsels = ldo_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LDO1_SHIFT), + .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, + LDO1_VSEL_SHIFT), + .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, + LDO1_ILIM_SHIFT), + }, + { + .name = "LDO2", + .n_voltages = ARRAY_SIZE(ldo2_voltages), + .voltages = ldo2_voltages, + .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), + .ilimsels = ldo_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LDO2_SHIFT), + .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, + LDO2_VSEL_SHIFT), + .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, + LDO2_ILIM_SHIFT), + }, + { + .name = "USB", + .flags = FIXED_VOLTAGE, + .fixed_voltage = 5000000, + .n_ilimsels = ARRAY_SIZE(usb_ilimsel), + .ilimsels = usb_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_USB_SHIFT), + .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK, + USB_ILIM_SHIFT), + }, + { + .name = "LCD", + .flags = FIXED_VOLTAGE | FIXED_ILIMSEL, + .fixed_voltage = 5000000, + .fixed_ilimsel = 400000, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LCD_SHIFT), + }, +}; + +static int list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return selector ? -EINVAL : info->fixed_voltage; + + return ((selector < info->n_voltages) ? + info->voltages[selector] : -EINVAL); +} + +static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) +{ + const struct supply_info *info; + struct tps6524x *hw; + unsigned i; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return -EINVAL; + + for (i = 0; i < info->n_voltages; i++) + if (min_uV <= info->voltages[i] && + max_uV >= info->voltages[i]) + break; + + if (i >= info->n_voltages) + i = info->n_voltages - 1; + + *selector = info->voltages[i]; + + return write_field(hw, &info->voltage, i); +} + +static int get_voltage(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + int ret; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return info->fixed_voltage; + + ret = read_field(hw, &info->voltage); + if (ret < 0) + return ret; + if (WARN_ON(ret >= info->n_voltages)) + return -EIO; + + return info->voltages[ret]; +} + +static int set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + const struct supply_info *info; + struct tps6524x *hw; + int i; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_ILIMSEL) + return -EINVAL; + + for (i = 0; i < info->n_ilimsels; i++) + if (min_uA <= info->ilimsels[i] && + max_uA >= info->ilimsels[i]) + break; + + if (i >= info->n_ilimsels) + return -EINVAL; + + return write_field(hw, &info->ilimsel, i); +} + +static int get_current_limit(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + int ret; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_ILIMSEL) + return info->fixed_ilimsel; + + ret = read_field(hw, &info->ilimsel); + if (ret < 0) + return ret; + if (WARN_ON(ret >= info->n_ilimsels)) + return -EIO; + + return info->ilimsels[ret]; +} + +static int enable_supply(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return write_field(hw, &info->enable, 1); +} + +static int disable_supply(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return write_field(hw, &info->enable, 0); +} + +static int is_supply_enabled(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return read_field(hw, &info->enable); +} + +static struct regulator_ops regulator_ops = { + .is_enabled = is_supply_enabled, + .enable = enable_supply, + .disable = disable_supply, + .get_voltage = get_voltage, + .set_voltage = set_voltage, + .list_voltage = list_voltage, + .set_current_limit = set_current_limit, + .get_current_limit = get_current_limit, +}; + +static int __devexit pmic_remove(struct spi_device *spi) +{ + struct tps6524x *hw = spi_get_drvdata(spi); + int i; + + if (!hw) + return 0; + for (i = 0; i < N_REGULATORS; i++) { + if (hw->rdev[i]) + regulator_unregister(hw->rdev[i]); + hw->rdev[i] = NULL; + } + spi_set_drvdata(spi, NULL); + kfree(hw); + return 0; +} + +static int __devinit pmic_probe(struct spi_device *spi) +{ + struct tps6524x *hw; + struct device *dev = &spi->dev; + const struct supply_info *info = supply_info; + struct regulator_init_data *init_data; + int ret = 0, i; + + init_data = dev->platform_data; + if (!init_data) { + dev_err(dev, "could not find regulator platform data\n"); + return -EINVAL; + } + + hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL); + if (!hw) { + dev_err(dev, "cannot allocate regulator private data\n"); + return -ENOMEM; + } + spi_set_drvdata(spi, hw); + + memset(hw, 0, sizeof(struct tps6524x)); + hw->dev = dev; + hw->spi = spi_dev_get(spi); + mutex_init(&hw->lock); + + for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { + hw->desc[i].name = info->name; + hw->desc[i].id = i; + hw->desc[i].n_voltages = info->n_voltages; + hw->desc[i].ops = ®ulator_ops; + hw->desc[i].type = REGULATOR_VOLTAGE; + hw->desc[i].owner = THIS_MODULE; + + if (info->flags & FIXED_VOLTAGE) + hw->desc[i].n_voltages = 1; + + hw->rdev[i] = regulator_register(&hw->desc[i], dev, + init_data, hw); + if (IS_ERR(hw->rdev[i])) { + ret = PTR_ERR(hw->rdev[i]); + hw->rdev[i] = NULL; + goto fail; + } + } + + return 0; + +fail: + pmic_remove(spi); + return ret; +} + +static struct spi_driver pmic_driver = { + .probe = pmic_probe, + .remove = __devexit_p(pmic_remove), + .driver = { + .name = "tps6524x", + .owner = THIS_MODULE, + }, +}; + +static int __init pmic_driver_init(void) +{ + return spi_register_driver(&pmic_driver); +} +module_init(pmic_driver_init); + +static void __exit pmic_driver_exit(void) +{ + spi_unregister_driver(&pmic_driver); +} +module_exit(pmic_driver_exit); + +MODULE_DESCRIPTION("TPS6524X PMIC Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:tps6524x"); diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 6d20b0454a1d..bb04a75a4c98 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -85,7 +85,8 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev, static int __tps6586x_ldo_set_voltage(struct device *parent, struct tps6586x_regulator *ri, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { int val, uV; uint8_t mask; @@ -100,6 +101,8 @@ static int __tps6586x_ldo_set_voltage(struct device *parent, /* use the first in-range value */ if (min_uV <= uV && uV <= max_uV) { + *selector = val; + val <<= ri->volt_shift; mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; @@ -111,12 +114,13 @@ static int __tps6586x_ldo_set_voltage(struct device *parent, } static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); - return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV); + return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, + selector); } static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) @@ -140,13 +144,14 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) } static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); int ret; - ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV); + ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, + selector); if (ret) return ret; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index a57262a4fa6c..bd332cf1cc3f 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -329,7 +329,8 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) } static int -twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel; @@ -345,9 +346,11 @@ twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) /* REVISIT for VAUX2, first match may not be best/lowest */ /* use the first in-range value */ - if (min_uV <= uV && uV <= max_uV) + if (min_uV <= uV && uV <= max_uV) { + *selector = vsel; return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); + } } return -EDOM; @@ -389,7 +392,8 @@ static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) } static int -twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel; @@ -402,6 +406,7 @@ twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) * mV = 1000mv + 100mv * (vsel - 1) */ vsel = (min_uV/1000 - 1000)/100 + 1; + *selector = vsel; return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); } diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index dbfaf5945e48..8b0d2c4bde91 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -302,7 +302,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) } static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -314,6 +314,8 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, if (vsel < 0) return vsel; + *selector = vsel; + /* If this value is already set then do a GPIO update if we can */ if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 0); @@ -375,14 +377,14 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel); } -static int wm831x_buckv_get_voltage(struct regulator_dev *rdev) +static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); if (dcdc->dvs_gpio && dcdc->dvs_gpio_state) - return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel); + return dcdc->dvs_vsel; else - return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel); + return dcdc->on_vsel; } /* Current limit options */ @@ -424,7 +426,7 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) static struct regulator_ops wm831x_buckv_ops = { .set_voltage = wm831x_buckv_set_voltage, - .get_voltage = wm831x_buckv_get_voltage, + .get_voltage_sel = wm831x_buckv_get_voltage_sel, .list_voltage = wm831x_buckv_list_voltage, .set_suspend_voltage = wm831x_buckv_set_suspend_voltage, .set_current_limit = wm831x_buckv_set_current_limit, @@ -636,7 +638,7 @@ static int wm831x_buckp_list_voltage(struct regulator_dev *rdev, } static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, int *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -650,16 +652,20 @@ static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel); } static int wm831x_buckp_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; - return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, @@ -667,11 +673,12 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; + unsigned selector; - return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV); + return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) +static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -682,12 +689,12 @@ static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - return wm831x_buckp_list_voltage(rdev, val & WM831X_DC3_ON_VSEL_MASK); + return val & WM831X_DC3_ON_VSEL_MASK; } static struct regulator_ops wm831x_buckp_ops = { .set_voltage = wm831x_buckp_set_voltage, - .get_voltage = wm831x_buckp_get_voltage, + .get_voltage_sel = wm831x_buckp_get_voltage_sel, .list_voltage = wm831x_buckp_list_voltage, .set_suspend_voltage = wm831x_buckp_set_suspend_voltage, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9edf8f692341..c94fc5b7cd5b 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -113,7 +113,8 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, } static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -133,16 +134,20 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel); } static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -150,11 +155,12 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + unsigned int selector; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -167,7 +173,7 @@ static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO1_ON_VSEL_MASK; - return wm831x_gp_ldo_list_voltage(rdev, ret); + return ret; } static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev) @@ -287,7 +293,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { .list_voltage = wm831x_gp_ldo_list_voltage, - .get_voltage = wm831x_gp_ldo_get_voltage, + .get_voltage_sel = wm831x_gp_ldo_get_voltage_sel, .set_voltage = wm831x_gp_ldo_set_voltage, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, .get_mode = wm831x_gp_ldo_get_mode, @@ -413,7 +419,8 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, } static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -433,16 +440,19 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel); } static int wm831x_aldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; - return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -450,11 +460,12 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + unsigned int selector; - return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -467,7 +478,7 @@ static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO7_ON_VSEL_MASK; - return wm831x_aldo_list_voltage(rdev, ret); + return ret; } static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev) @@ -548,7 +559,7 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_aldo_ops = { .list_voltage = wm831x_aldo_list_voltage, - .get_voltage = wm831x_aldo_get_voltage, + .get_voltage_sel = wm831x_aldo_get_voltage_sel, .set_voltage = wm831x_aldo_set_voltage, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, .get_mode = wm831x_aldo_get_mode, @@ -666,7 +677,8 @@ static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev, static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -680,16 +692,20 @@ static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel); } static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -697,11 +713,12 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL; + unsigned selector; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -714,7 +731,7 @@ static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO11_ON_VSEL_MASK; - return wm831x_alive_ldo_list_voltage(rdev, ret); + return ret; } static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) @@ -736,7 +753,7 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_alive_ldo_ops = { .list_voltage = wm831x_alive_ldo_list_voltage, - .get_voltage = wm831x_alive_ldo_get_voltage, + .get_voltage_sel = wm831x_alive_ldo_get_voltage_sel, .set_voltage = wm831x_alive_ldo_set_voltage, .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage, .get_status = wm831x_alive_ldo_get_status, diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index fe4b8a8a9dfd..1bcb22c44095 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -360,7 +360,7 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode, EXPORT_SYMBOL_GPL(wm8350_isink_set_flash); static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) + int max_uV, unsigned *selector) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, dcdc = rdev_get_id(rdev), mV, @@ -397,17 +397,18 @@ static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, return -EINVAL; } + *selector = mV; + /* all DCDCs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; wm8350_reg_write(wm8350, volt_reg, val | mV); return 0; } -static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev) +static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, dcdc = rdev_get_id(rdev); - u16 val; switch (dcdc) { case WM8350_DCDC_1: @@ -429,8 +430,7 @@ static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev) } /* all DCDCs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; - return wm8350_dcdc_val_to_mvolts(val) * 1000; + return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; } static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev, @@ -754,7 +754,7 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev) } static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) + int max_uV, unsigned *selector) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000, @@ -797,17 +797,18 @@ static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, return -EINVAL; } + *selector = mV; + /* all LDOs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; wm8350_reg_write(wm8350, volt_reg, val | mV); return 0; } -static int wm8350_ldo_get_voltage(struct regulator_dev *rdev) +static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, ldo = rdev_get_id(rdev); - u16 val; switch (ldo) { case WM8350_LDO_1: @@ -827,8 +828,7 @@ static int wm8350_ldo_get_voltage(struct regulator_dev *rdev) } /* all LDOs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; - return wm8350_ldo_val_to_mvolts(val) * 1000; + return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; } static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, @@ -1225,7 +1225,7 @@ static int wm8350_ldo_is_enabled(struct regulator_dev *rdev) static struct regulator_ops wm8350_dcdc_ops = { .set_voltage = wm8350_dcdc_set_voltage, - .get_voltage = wm8350_dcdc_get_voltage, + .get_voltage_sel = wm8350_dcdc_get_voltage_sel, .list_voltage = wm8350_dcdc_list_voltage, .enable = wm8350_dcdc_enable, .disable = wm8350_dcdc_disable, @@ -1249,7 +1249,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = { static struct regulator_ops wm8350_ldo_ops = { .set_voltage = wm8350_ldo_set_voltage, - .get_voltage = wm8350_ldo_get_voltage, + .get_voltage_sel = wm8350_ldo_get_voltage_sel, .list_voltage = wm8350_ldo_list_voltage, .enable = wm8350_ldo_enable, .disable = wm8350_ldo_disable, diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 924c7eb29ee9..b42d01cef35a 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -67,7 +67,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev) } static int wm8400_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; @@ -93,6 +93,8 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev, val += 0xf; } + *selector = val; + return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev), WM8400_LDO1_VSEL_MASK, val); } @@ -156,7 +158,7 @@ static int wm8400_dcdc_get_voltage(struct regulator_dev *dev) } static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; @@ -171,6 +173,8 @@ static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, return -EINVAL; BUG_ON(850000 + (25000 * val) < min_uV); + *selector = val; + return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, WM8400_DC1_VSEL_MASK, val); } diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 03713bc66e4a..35b2958d5106 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -86,7 +86,7 @@ static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 2400000; } -static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) +static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int val; @@ -95,13 +95,11 @@ static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; - - return wm8994_ldo1_list_voltage(rdev, val); + return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; } static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *s) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; @@ -111,6 +109,7 @@ static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, if (v < 0 || v > max_uV) return -EINVAL; + *s = selector; selector <<= WM8994_LDO1_VSEL_SHIFT; return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1, @@ -124,20 +123,29 @@ static struct regulator_ops wm8994_ldo1_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo1_list_voltage, - .get_voltage = wm8994_ldo1_get_voltage, + .get_voltage_sel = wm8994_ldo1_get_voltage_sel, .set_voltage = wm8994_ldo1_set_voltage, }; static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, unsigned int selector) { + struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); + if (selector > WM8994_LDO2_MAX_SELECTOR) return -EINVAL; - return (selector * 100000) + 900000; + switch (ldo->wm8994->type) { + case WM8994: + return (selector * 100000) + 900000; + case WM8958: + return (selector * 100000) + 1000000; + default: + return -EINVAL; + } } -static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) +static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int val; @@ -146,22 +154,31 @@ static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; - - return wm8994_ldo2_list_voltage(rdev, val); + return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; } static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *s) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; - selector = (min_uV - 900000) / 100000; + switch (ldo->wm8994->type) { + case WM8994: + selector = (min_uV - 900000) / 100000; + break; + case WM8958: + selector = (min_uV - 1000000) / 100000; + break; + default: + return -EINVAL; + } + v = wm8994_ldo2_list_voltage(rdev, selector); if (v < 0 || v > max_uV) return -EINVAL; + *s = selector; selector <<= WM8994_LDO2_VSEL_SHIFT; return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2, @@ -175,7 +192,7 @@ static struct regulator_ops wm8994_ldo2_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo2_list_voltage, - .get_voltage = wm8994_ldo2_get_voltage, + .get_voltage_sel = wm8994_ldo2_get_voltage_sel, .set_voltage = wm8994_ldo2_set_voltage, }; diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 7e6ce626b7f1..c7ff8df347e7 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -36,6 +36,7 @@ #include <linux/platform_device.h> #include <linux/mod_devicetable.h> #include <linux/log2.h> +#include <linux/pm.h> /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> @@ -851,7 +852,7 @@ static void __exit cmos_do_remove(struct device *dev) #ifdef CONFIG_PM -static int cmos_suspend(struct device *dev, pm_message_t mesg) +static int cmos_suspend(struct device *dev) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char tmp; @@ -899,7 +900,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) */ static inline int cmos_poweroff(struct device *dev) { - return cmos_suspend(dev, PMSG_HIBERNATE); + return cmos_suspend(dev); } static int cmos_resume(struct device *dev) @@ -946,9 +947,9 @@ static int cmos_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); + #else -#define cmos_suspend NULL -#define cmos_resume NULL static inline int cmos_poweroff(struct device *dev) { @@ -1078,7 +1079,7 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp) static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg) { - return cmos_suspend(&pnp->dev, mesg); + return cmos_suspend(&pnp->dev); } static int cmos_pnp_resume(struct pnp_dev *pnp) @@ -1158,8 +1159,9 @@ static struct platform_driver cmos_platform_driver = { .shutdown = cmos_platform_shutdown, .driver = { .name = (char *) driver_name, - .suspend = cmos_suspend, - .resume = cmos_resume, +#ifdef CONFIG_PM + .pm = &cmos_pm_ops, +#endif } }; diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c index 657403ebd54a..0ec3f588a255 100644 --- a/drivers/rtc/rtc-max6902.c +++ b/drivers/rtc/rtc-max6902.c @@ -139,12 +139,13 @@ static int __devinit max6902_probe(struct spi_device *spi) if (IS_ERR(rtc)) return PTR_ERR(rtc); + dev_set_drvdata(&spi->dev, rtc); return 0; } static int __devexit max6902_remove(struct spi_device *spi) { - struct rtc_device *rtc = platform_get_drvdata(spi); + struct rtc_device *rtc = dev_get_drvdata(&spi->dev); rtc_device_unregister(rtc); return 0; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 73377b0d65da..e72b523c79a5 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -429,13 +429,14 @@ fail1: fail0: iounmap(rtc_base); fail: - release_resource(mem); + release_mem_region(mem->start, resource_size(mem)); return -EIO; } static int __exit omap_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); + struct resource *mem = dev_get_drvdata(&rtc->dev); device_init_wakeup(&pdev->dev, 0); @@ -447,8 +448,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) if (omap_rtc_timer != omap_rtc_alarm) free_irq(omap_rtc_alarm, rtc); - release_resource(dev_get_drvdata(&rtc->dev)); rtc_device_unregister(rtc); + iounmap(rtc_base); + release_mem_region(mem->start, resource_size(mem)); return 0; } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 09e7a053c844..30b2a820e670 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -841,7 +841,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) } /** - * Emit buffer of a lan comand. + * Emit buffer of a lan command. */ static void lcs_lancmd_timeout(unsigned long data) diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 46342fee394d..303dde09d294 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -317,7 +317,7 @@ static void zfcp_act_eval_err(struct zfcp_adapter *adapter, u32 table) /** * zfcp_cfdc_port_denied - Process "access denied" for port - * @port: The port where the acces has been denied + * @port: The port where the access has been denied * @qual: The FSF status qualifier for the access denied FSF status */ void zfcp_cfdc_port_denied(struct zfcp_port *port, diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index dc5ac6e528c4..a391090a17c5 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -416,7 +416,7 @@ static u8 orc_load_firmware(struct orc_host * host) /* Go back and check they match */ outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */ - bios_addr -= 0x1000; /* Reset the BIOS adddress */ + bios_addr -= 0x1000; /* Reset the BIOS address */ for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */ i < 0x1000; /* Firmware code size = 4K */ i++, bios_addr++) { diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index afc9aeba5edb..060ac4bd5a14 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -91,7 +91,7 @@ void aac_fib_map_free(struct aac_dev *dev) * aac_fib_setup - setup the fibs * @dev: Adapter to set up * - * Allocate the PCI space for the fibs, map it and then intialise the + * Allocate the PCI space for the fibs, map it and then initialise the * fib area, the unmapped fib data and also the free list */ diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq index 5997e7c3a191..1565be9ebd49 100644 --- a/drivers/scsi/aic7xxx_old/aic7xxx.seq +++ b/drivers/scsi/aic7xxx_old/aic7xxx.seq @@ -1178,7 +1178,7 @@ notFound: /* * Retrieve an SCB by SCBID first searching the disconnected list falling * back to DMA'ing the SCB down from the host. This routine assumes that - * ARG_1 is the SCBID of interrest and that SINDEX is the position in the + * ARG_1 is the SCBID of interest and that SINDEX is the position in the * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, * we go directly to the host for the SCB. */ diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index 28aaf349c111..40273a747d29 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -1689,7 +1689,7 @@ #define PHY_START_CAL 0x01 /* - * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC) + * HST_PCIX2 Registers, Address Range: (0x00-0xFC) */ #define PCIX_REG_BASE_ADR 0xB8040000 @@ -1802,7 +1802,7 @@ #define PCIC_TP_CTRL 0xFC /* - * EXSI Registers, Addresss Range: (0x00-0xFC) + * EXSI Registers, Address Range: (0x00-0xFC) */ #define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index c43698b1cb64..29593275201a 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -867,7 +867,7 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, * resources they have with this SCB, and then call this one at the * end of their timeout function. To do this, one should initialize * the ascb->timer.{function, data, expires} prior to calling the post - * funcion. The timer is started by the post function. + * function. The timer is started by the post function. */ void asd_ascb_timedout(unsigned long data) { diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index 74374618010c..390168f62a13 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -797,7 +797,7 @@ static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) int j; /* Start from Page 1 of Mode 0 and 1. */ moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; - /* All the fields of page 1 can be intialized to 0. */ + /* All the fields of page 1 can be initialized to 0. */ for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); } @@ -938,7 +938,7 @@ static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) asd_write_reg_dword(asd_ha, SCBPRO, 0); asd_write_reg_dword(asd_ha, CSEQCON, 0); - /* Intialize CSEQ Mode 11 Interrupt Vectors. + /* Initialize CSEQ Mode 11 Interrupt Vectors. * The addresses are 16 bit wide and in dword units. * The values of their macros are in byte units. * Thus we have to divide by 4. */ @@ -961,7 +961,7 @@ static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); for (i = 0; i < 8; i++) { - /* Intialize Mode n Link m Interrupt Enable. */ + /* Initialize Mode n Link m Interrupt Enable. */ asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); /* Initialize Mode n Request Mailbox. */ asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 9c410b21db6d..c0353cdca929 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -1838,7 +1838,7 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_ABORT: /* - * IO is alraedy being cleaned up implicitly + * IO is already being cleaned up implicitly */ ioim->io_cbfn = __bfa_cb_ioim_abort; break; diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 4e2eb92ba028..43fa986bb586 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -5646,7 +5646,7 @@ bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status) switch (status) { case BFA_STATUS_OK: /* - * Initialiaze the V-Port fields + * Initialize the V-Port fields */ __vport_fcid(vport) = vport->lps->lp_pid; vport->vport_stats.fdisc_accepts++; diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 8f1b5c8bf903..b0f8523e665f 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -3796,7 +3796,7 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, * adapter_add_device - Adds the device instance to the adaptor instance. * * @acb: The adapter device to be updated - * @dcb: A newly created and intialised device instance to add. + * @dcb: A newly created and initialised device instance to add. **/ static void adapter_add_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) @@ -4498,7 +4498,7 @@ static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb) * init_adapter - Grab the resource for the card, setup the adapter * information, set the card into a known state, create the various * tables etc etc. This basically gets all adapter information all up - * to date, intialised and gets the chip in sync with it. + * to date, initialised and gets the chip in sync with it. * * @host: This hosts adapter structure * @io_port: The base I/O port @@ -4789,7 +4789,7 @@ static void banner_display(void) * that it finds in the system. The pci_dev strcuture indicates which * instance we are being called from. * - * @dev: The PCI device to intialize. + * @dev: The PCI device to initialize. * @id: Looks like a pointer to the entry in our pci device table * that was actually matched by the PCI subsystem. * @@ -4860,7 +4860,7 @@ fail: * dc395x_remove_one - Called to remove a single instance of the * adapter. * - * @dev: The PCI device to intialize. + * @dev: The PCI device to initialize. **/ static void __devexit dc395x_remove_one(struct pci_dev *dev) { diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index cdc06cda76e5..5962d1a5a674 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1250,7 +1250,7 @@ static void fc_lun_reset_send(unsigned long data) /** * fc_lun_reset() - Send a LUN RESET command to a device * and wait for the reply - * @lport: The local port to sent the comand on + * @lport: The local port to sent the command on * @fsp: The FCP packet that identifies the LUN to be reset * @id: The SCSI command ID * @lun: The LUN ID to be reset diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c06491b5862f..3512abb8a587 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1335,7 +1335,7 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ } /** - * lpfc_param_init - Intializes a cfg attribute + * lpfc_param_init - Initializes a cfg attribute * * Description: * Macro that given an attr e.g. hba_queue_depth expands diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f9f160ab2ee9..bb015960dbc9 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -2852,7 +2852,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) if (unlikely(!fcf_record)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2554 Could not allocate memmory for " + "2554 Could not allocate memory for " "fcf record\n"); rc = -ENODEV; goto out; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 462242dcdd0a..6d0b36aa3389 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -8071,7 +8071,7 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) * the HBA. */ - /* HBA interrupt will be diabled after this call */ + /* HBA interrupt will be disabled after this call */ lpfc_sli_hba_down(phba); /* Stop kthread signal shall trigger work_done one more time */ kthread_stop(phba->worker_thread); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 634b2fea9c4d..a359d2b873ce 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10172,7 +10172,7 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) * lpfc_sli4_queue_free - free a queue structure and associated memory * @queue: The queue structure to free. * - * This function frees a queue structure and the DMAable memeory used for + * This function frees a queue structure and the DMAable memory used for * the host resident queue. This function must be called after destroying the * queue on the HBA. **/ diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index f5644745e24e..853411911b2e 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -13,7 +13,7 @@ */ /* - * Comand coalescing - This feature allows the driver to be able to combine + * Command coalescing - This feature allows the driver to be able to combine * two or more commands and issue as one command in order to boost I/O * performance. Useful if the nature of the I/O is sequential. It is not very * useful for random natured I/Os. diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index a7008c0c24f9..25506c777381 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -224,7 +224,7 @@ mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd, { int err; - /* inconsistant: mraid_mm_compat_ioctl doesn't take the BKL */ + /* inconsistent: mraid_mm_compat_ioctl doesn't take the BKL */ mutex_lock(&mraid_mm_mutex); err = mraid_mm_ioctl(filep, cmd, arg); mutex_unlock(&mraid_mm_mutex); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index f8c86b28f03f..b95285f3383f 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -603,7 +603,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) #endif intx: - /* intialize the INT-X interrupt */ + /* initialize the INT-X interrupt */ rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost)); return rc; diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index d53e6503c6d5..a2ed201885ae 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -477,7 +477,7 @@ EXPORT_SYMBOL_GPL(scsi_nl_remove_driver); /** - * scsi_netlink_init - Called by SCSI subsystem to intialize + * scsi_netlink_init - Called by SCSI subsystem to initialize * the SCSI transport netlink interface * **/ diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 4c68d36f9ac2..490ce213204e 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -864,13 +864,15 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) error = device_add(&sdev->sdev_gendev); if (error) { - printk(KERN_INFO "error 1\n"); + sdev_printk(KERN_INFO, sdev, + "failed to add device: %d\n", error); return error; } device_enable_async_suspend(&sdev->sdev_dev); error = device_add(&sdev->sdev_dev); if (error) { - printk(KERN_INFO "error 2\n"); + sdev_printk(KERN_INFO, sdev, + "failed to add class device: %d\n", error); device_del(&sdev->sdev_gendev); return error; } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 6b97ded9d45d..b4543f575f46 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1866,7 +1866,7 @@ static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev) * * This routine is similar to sym_set_workarounds(), except * that, at this point, we already know that the device was - * successfully intialized at least once before, and so most + * successfully initialized at least once before, and so most * of the steps taken there are un-needed here. */ static void sym2_reset_workarounds(struct pci_dev *pdev) diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index a067046c9da2..1a478bf88c9d 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -341,9 +341,9 @@ static void atmel_spi_next_message(struct spi_master *master) /* * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma: * - The buffer is either valid for CPU access, else NULL - * - If the buffer is valid, so is its DMA addresss + * - If the buffer is valid, so is its DMA address * - * This driver manages the dma addresss unless message->is_dma_mapped. + * This driver manages the dma address unless message->is_dma_mapped. */ static int atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 4e6245e67995..603428213d21 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -38,7 +38,7 @@ /* - * This supports acccess to SPI devices using normal userspace I/O calls. + * This supports access to SPI devices using normal userspace I/O calls. * Note that while traditional UNIX/POSIX I/O semantics are half duplex, * and often mask message boundaries, full SPI support requires full duplex * transfers. There are several kinds of internal message boundaries to diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e2d586903432..5c8fcfc42c3e 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -123,6 +123,8 @@ source "drivers/staging/sep/Kconfig" source "drivers/staging/iio/Kconfig" +source "drivers/staging/cs5535_gpio/Kconfig" + source "drivers/staging/zram/Kconfig" source "drivers/staging/wlags49_h2/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index c7d222413c07..d53886317826 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ +obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ diff --git a/drivers/staging/cs5535_gpio/Kconfig b/drivers/staging/cs5535_gpio/Kconfig new file mode 100644 index 000000000000..a1b3a8d2b866 --- /dev/null +++ b/drivers/staging/cs5535_gpio/Kconfig @@ -0,0 +1,11 @@ +config CS5535_GPIO + tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)" + depends on X86_32 + help + Note: this driver is DEPRECATED. Please use the cs5535-gpio module + in the GPIO section instead (CONFIG_GPIO_CS5535). + + Give userspace access to the GPIO pins on the AMD CS5535 and + CS5536 Geode companion devices. + + If compiled as a module, it will be called cs5535_gpio. diff --git a/drivers/staging/cs5535_gpio/Makefile b/drivers/staging/cs5535_gpio/Makefile new file mode 100644 index 000000000000..d67c4b85f191 --- /dev/null +++ b/drivers/staging/cs5535_gpio/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o diff --git a/drivers/staging/cs5535_gpio/TODO b/drivers/staging/cs5535_gpio/TODO new file mode 100644 index 000000000000..98d1cd1e2363 --- /dev/null +++ b/drivers/staging/cs5535_gpio/TODO @@ -0,0 +1,6 @@ +This is an obsolete driver for some the CS5535 and CS5536 southbridge GPIOs. +It has been replaced by a driver that makes use of the Linux GPIO subsystem. +Please switch to that driver, and let dilinger@queued.net know if there's +anything missing from the new driver. + +This driver is scheduled for removal in 2.6.40. diff --git a/drivers/char/cs5535_gpio.c b/drivers/staging/cs5535_gpio/cs5535_gpio.c index 0cf1e5fad9ab..0cf1e5fad9ab 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/staging/cs5535_gpio/cs5535_gpio.c diff --git a/drivers/staging/msm/msm_fb_bl.c b/drivers/staging/msm/msm_fb_bl.c index 033fc9486e01..2a8077511fc0 100644 --- a/drivers/staging/msm/msm_fb_bl.c +++ b/drivers/staging/msm/msm_fb_bl.c @@ -42,7 +42,7 @@ static int msm_fb_bl_update_status(struct backlight_device *pbd) return 0; } -static struct backlight_ops msm_fb_bl_ops = { +static const struct backlight_ops msm_fb_bl_ops = { .get_brightness = msm_fb_bl_get_brightness, .update_status = msm_fb_bl_update_status, }; diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO index ac2d3d023715..35f9cda7be11 100644 --- a/drivers/staging/olpc_dcon/TODO +++ b/drivers/staging/olpc_dcon/TODO @@ -1,6 +1,5 @@ TODO: - checkpatch.pl cleanups - - port geode gpio calls to newer cs5535 API - see if vx855 gpio API can be made similar enough to cs5535 so we can share more code - allow simultaneous XO-1 and XO-1.5 support diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 4ca45ec7fd84..9f26dc9408bb 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -27,7 +27,6 @@ #include <asm/uaccess.h> #include <linux/ctype.h> #include <linux/reboot.h> -#include <linux/gpio.h> #include <asm/tsc.h> #include <asm/olpc.h> @@ -49,7 +48,7 @@ struct dcon_platform_data { int (*init)(void); void (*bus_stabilize_wiggle)(void); void (*set_dconload)(int); - int (*read_status)(void); + u8 (*read_status)(void); }; static struct dcon_platform_data *pdata; @@ -615,7 +614,7 @@ static struct device_attribute dcon_device_files[] = { __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store), }; -static struct backlight_ops dcon_bl_ops = { +static const struct backlight_ops dcon_bl_ops = { .get_brightness = dconbl_get, .update_status = dconbl_set }; diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h index 6453ca4ba0ee..e566d213da2a 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.h +++ b/drivers/staging/olpc_dcon/olpc_dcon.h @@ -29,26 +29,6 @@ #define DCON_REG_SCAN_INT 9 #define DCON_REG_BRIGHT 10 -/* GPIO registers (CS5536) */ - -#define MSR_LBAR_GPIO 0x5140000C - -#define GPIOx_OUT_VAL 0x00 -#define GPIOx_OUT_EN 0x04 -#define GPIOx_IN_EN 0x20 -#define GPIOx_INV_EN 0x24 -#define GPIOx_IN_FLTR_EN 0x28 -#define GPIOx_EVNTCNT_EN 0x2C -#define GPIOx_READ_BACK 0x30 -#define GPIOx_EVNT_EN 0x38 -#define GPIOx_NEGEDGE_EN 0x44 -#define GPIOx_NEGEDGE_STS 0x4C -#define GPIO_FLT7_AMNT 0xD8 -#define GPIO_MAP_X 0xE0 -#define GPIO_MAP_Y 0xE4 -#define GPIO_FE7_SEL 0xF7 - - /* Status values */ #define DCONSTAT_SCANINT 0 diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index 779fb7d7b30c..043198dc6ff7 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -10,54 +10,70 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ - +#include <linux/cs5535.h> +#include <linux/gpio.h> #include <asm/olpc.h> #include "olpc_dcon.h" -/* Base address of the GPIO registers */ -static unsigned long gpio_base; - -/* - * List of GPIOs that we care about: - * (in) GPIO12 -- DCONBLANK - * (in) GPIO[56] -- DCONSTAT[01] - * (out) GPIO11 -- DCONLOAD - */ - -#define IN_GPIOS ((1<<5) | (1<<6) | (1<<7) | (1<<12)) -#define OUT_GPIOS (1<<11) - static int dcon_init_xo_1(void) { - unsigned long lo, hi; unsigned char lob; - rdmsr(MSR_LBAR_GPIO, lo, hi); - - /* Check the mask and whether GPIO is enabled (sanity check) */ - if (hi != 0x0000f001) { - printk(KERN_ERR "GPIO not enabled -- cannot use DCON\n"); - return -ENODEV; + if (gpio_request(OLPC_GPIO_DCON_STAT0, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request STAT0 GPIO\n"); + return -EIO; + } + if (gpio_request(OLPC_GPIO_DCON_STAT1, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request STAT1 GPIO\n"); + goto err_gp_stat1; + } + if (gpio_request(OLPC_GPIO_DCON_IRQ, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request IRQ GPIO\n"); + goto err_gp_irq; + } + if (gpio_request(OLPC_GPIO_DCON_LOAD, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request LOAD GPIO\n"); + goto err_gp_load; + } + if (gpio_request(OLPC_GPIO_DCON_BLANK, "OLPC-DCON")) { + printk(KERN_ERR "olpc-dcon: failed to request BLANK GPIO\n"); + goto err_gp_blank; } - - /* Mask off the IO base address */ - gpio_base = lo & 0x0000ff00; /* Turn off the event enable for GPIO7 just to be safe */ - outl(1 << (16+7), gpio_base + GPIOx_EVNT_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); + + /* + * Determine the current state by reading the GPIO bit; earlier + * stages of the boot process have established the state. + * + * Note that we read GPIO_OUPUT_VAL rather than GPIO_READ_BACK here; + * this is because OFW will disable input for the pin and set a value.. + * READ_BACK will only contain a valid value if input is enabled and + * then a value is set. So, future readings of the pin can use + * READ_BACK, but the first one cannot. Awesome, huh? + */ + dcon_source = cs5535_gpio_isset(OLPC_GPIO_DCON_LOAD, GPIO_OUTPUT_VAL) + ? DCON_SOURCE_CPU + : DCON_SOURCE_DCON; + dcon_pending = dcon_source; /* Set the directions for the GPIO pins */ - outl(OUT_GPIOS | (IN_GPIOS << 16), gpio_base + GPIOx_OUT_EN); - outl(IN_GPIOS | (OUT_GPIOS << 16), gpio_base + GPIOx_IN_EN); + gpio_direction_input(OLPC_GPIO_DCON_STAT0); + gpio_direction_input(OLPC_GPIO_DCON_STAT1); + gpio_direction_input(OLPC_GPIO_DCON_IRQ); + gpio_direction_input(OLPC_GPIO_DCON_BLANK); + gpio_direction_output(OLPC_GPIO_DCON_LOAD, + dcon_source == DCON_SOURCE_CPU); /* Set up the interrupt mappings */ /* Set the IRQ to pair 2 */ - geode_gpio_event_irq(OLPC_GPIO_DCON_IRQ, 2); + cs5535_gpio_setup_event(OLPC_GPIO_DCON_IRQ, 2, 0); /* Enable group 2 to trigger the DCON interrupt */ - geode_gpio_set_irq(2, DCON_IRQ); + cs5535_gpio_set_irq(2, DCON_IRQ); /* Select edge level for interrupt (in PIC) */ lob = inb(0x4d0); @@ -65,52 +81,61 @@ static int dcon_init_xo_1(void) outb(lob, 0x4d0); /* Register the interupt handler */ - if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver)) - return -EIO; + if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", &dcon_driver)) { + printk(KERN_ERR "olpc-dcon: failed to request DCON's irq\n"); + goto err_req_irq; + } /* Clear INV_EN for GPIO7 (DCONIRQ) */ - outl((1<<(16+7)), gpio_base + GPIOx_INV_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_INVERT); /* Enable filter for GPIO12 (DCONBLANK) */ - outl(1<<(12), gpio_base + GPIOx_IN_FLTR_EN); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_FILTER); /* Disable filter for GPIO7 */ - outl(1<<(16+7), gpio_base + GPIOx_IN_FLTR_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_FILTER); /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ - - outl(1<<(16+7), gpio_base + GPIOx_EVNTCNT_EN); - outl(1<<(16+12), gpio_base + GPIOx_EVNTCNT_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_EVENT_COUNT); + cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_EVENT_COUNT); /* Add GPIO12 to the Filter Event Pair #7 */ - outb(12, gpio_base + GPIO_FE7_SEL); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_FE7_SEL); /* Turn off negative Edge Enable for GPIO12 */ - outl(1<<(16+12), gpio_base + GPIOx_NEGEDGE_EN); + cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_EN); /* Enable negative Edge Enable for GPIO7 */ - outl(1<<7, gpio_base + GPIOx_NEGEDGE_EN); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_EN); /* Zero the filter amount for Filter Event Pair #7 */ - outw(0, gpio_base + GPIO_FLT7_AMNT); + cs5535_gpio_set(0, GPIO_FLTR7_AMOUNT); /* Clear the negative edge status for GPIO7 and GPIO12 */ - outl((1<<7) | (1<<12), gpio_base+0x4c); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS); /* FIXME: Clear the posiitive status as well, just to be sure */ - outl((1<<7) | (1<<12), gpio_base+0x48); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS); /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ - outl((1<<(7))|(1<<12), gpio_base + GPIOx_EVNT_EN); - - /* Determine the current state by reading the GPIO bit */ - /* Earlier stages of the boot process have established the state */ - dcon_source = inl(gpio_base + GPIOx_OUT_VAL) & (1<<11) - ? DCON_SOURCE_CPU - : DCON_SOURCE_DCON; - dcon_pending = dcon_source; + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); + cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_EVENTS_ENABLE); return 0; + +err_req_irq: + gpio_free(OLPC_GPIO_DCON_BLANK); +err_gp_blank: + gpio_free(OLPC_GPIO_DCON_LOAD); +err_gp_load: + gpio_free(OLPC_GPIO_DCON_IRQ); +err_gp_irq: + gpio_free(OLPC_GPIO_DCON_STAT1); +err_gp_stat1: + gpio_free(OLPC_GPIO_DCON_STAT0); + return -EIO; } static void dcon_wiggle_xo_1(void) @@ -128,37 +153,44 @@ static void dcon_wiggle_xo_1(void) * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and * GPIO15. */ - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL); - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE); - geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); - geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2); - geode_gpio_clear(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_ENABLE); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX2); + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); + cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); for (x = 0; x < 16; x++) { udelay(5); - geode_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); + cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); udelay(5); - geode_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); } udelay(5); - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); - geode_gpio_set(OLPC_GPIO_SMB_CLK|OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); + cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); } static void dcon_set_dconload_1(int val) { - if (val) - outl(1<<11, gpio_base + GPIOx_OUT_VAL); - else - outl(1<<(11 + 16), gpio_base + GPIOx_OUT_VAL); + gpio_set_value(OLPC_GPIO_DCON_LOAD, val); } -static int dcon_read_status_xo_1(void) +static u8 dcon_read_status_xo_1(void) { - int status = inl(gpio_base + GPIOx_READ_BACK) >> 5; - + u8 status; + + status = gpio_get_value(OLPC_GPIO_DCON_STAT0); + status |= gpio_get_value(OLPC_GPIO_DCON_STAT1) << 1; + /* Clear the negative edge status for GPIO7 */ - outl(1 << 7, gpio_base + GPIOx_NEGEDGE_STS); + cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); return status; } diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c index cca6a235ef96..4f56098bb366 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c @@ -195,9 +195,9 @@ static void dcon_set_dconload_xo_1_5(int val) } } -static int dcon_read_status_xo_1_5(void) +static u8 dcon_read_status_xo_1_5(void) { - int status; + u8 status; if (!dcon_was_irq()) return -1; diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c index 9279897ff161..b2e918622088 100644 --- a/drivers/staging/pohmelfs/net.c +++ b/drivers/staging/pohmelfs/net.c @@ -413,7 +413,7 @@ static int pohmelfs_readdir_response(struct netfs_state *st) if (dentry) { alias = d_materialise_unique(dentry, &npi->vfs_inode); if (alias) - dput(dentry); + dput(alias); } dput(dentry); diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c index ac2bf11e1119..701e8d52a9fa 100644 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ b/drivers/staging/samsung-laptop/samsung-laptop.c @@ -269,7 +269,7 @@ static int update_status(struct backlight_device *bd) return 0; } -static struct backlight_ops backlight_ops = { +static const struct backlight_ops backlight_ops = { .get_brightness = get_brightness, .update_status = update_status, }; diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c index dd612f50749f..87a3a9bd5842 100644 --- a/drivers/staging/smbfs/dir.c +++ b/drivers/staging/smbfs/dir.c @@ -403,12 +403,6 @@ smb_delete_dentry(const struct dentry *dentry) void smb_new_dentry(struct dentry *dentry) { - struct smb_sb_info *server = server_from_dentry(dentry); - - if (server->mnt->flags & SMB_MOUNT_CASE) - d_set_d_op(dentry, &smbfs_dentry_operations_case); - else - d_set_d_op(dentry, &smbfs_dentry_operations); dentry->d_time = jiffies; } @@ -440,7 +434,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct smb_fattr finfo; struct inode *inode; int error; - struct smb_sb_info *server; error = -ENAMETOOLONG; if (dentry->d_name.len > SMB_MAXNAMELEN) @@ -468,12 +461,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) inode = smb_iget(dir->i_sb, &finfo); if (inode) { add_entry: - server = server_from_dentry(dentry); - if (server->mnt->flags & SMB_MOUNT_CASE) - d_set_d_op(dentry, &smbfs_dentry_operations_case); - else - d_set_d_op(dentry, &smbfs_dentry_operations); - d_add(dentry, inode); smb_renew_times(dentry); error = 0; diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c index 244319dc9702..0778589d9e9e 100644 --- a/drivers/staging/smbfs/inode.c +++ b/drivers/staging/smbfs/inode.c @@ -614,6 +614,10 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) printk(KERN_ERR "smbfs: failed to start smbiod\n"); goto out_no_smbiod; } + if (server->mnt->flags & SMB_MOUNT_CASE) + sb->s_d_op = &smbfs_dentry_operations_case; + else + sb->s_d_op = &smbfs_dentry_operations; /* * Keep the super block locked while we get the root inode. diff --git a/drivers/staging/smbfs/proto.h b/drivers/staging/smbfs/proto.h index 05939a6f43e6..3883cb16a3f6 100644 --- a/drivers/staging/smbfs/proto.h +++ b/drivers/staging/smbfs/proto.h @@ -38,6 +38,8 @@ extern void smb_install_null_ops(struct smb_ops *ops); extern const struct file_operations smb_dir_operations; extern const struct inode_operations smb_dir_inode_operations; extern const struct inode_operations smb_dir_inode_operations_unix; +extern const struct dentry_operations smbfs_dentry_operations_case; +extern const struct dentry_operations smbfs_dentry_operations; extern void smb_new_dentry(struct dentry *dentry); extern void smb_renew_times(struct dentry *dentry); /* cache.c */ diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 0d236f4bb8c2..b00101972f20 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -284,12 +284,11 @@ static int samplerate = 100; module_param(ixjdebug, int, 0); -static struct pci_device_id ixj_pci_tbl[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(ixj_pci_tbl) = { { PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { } }; - MODULE_DEVICE_TABLE(pci, ixj_pci_tbl); /************************************************************************ @@ -6581,7 +6580,8 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar case IXJCTL_SET_FILTER: if (copy_from_user(&jf, argp, sizeof(jf))) retval = -EFAULT; - retval = ixj_init_filter(j, &jf); + else + retval = ixj_init_filter(j, &jf); break; case IXJCTL_SET_FILTER_RAW: if (copy_from_user(&jfr, argp, sizeof(jfr))) diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 1210534822d6..5408186afc35 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1320,7 +1320,7 @@ static struct imx_udc_struct controller = { }; /******************************************************************************* - * USB gadged driver functions + * USB gadget driver functions ******************************************************************************* */ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 777972454e3e..1eca8b47ce3c 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -3086,7 +3086,7 @@ static void langwell_udc_remove(struct pci_dev *pdev) kfree(dev->ep); - /* diable IRQ handler */ + /* disable IRQ handler */ if (dev->got_irq) free_irq(pdev->irq, dev); @@ -3406,7 +3406,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) /* disable interrupt and set controller to stop state */ langwell_udc_stop(dev); - /* diable IRQ handler */ + /* disable IRQ handler */ if (dev->got_irq) free_irq(pdev->irq, dev); dev->got_irq = 0; diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 20092a27a1e8..12fd184226f2 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -98,13 +98,13 @@ void fhci_usb_enable_interrupt(struct fhci_usb *usb) usb->intr_nesting_cnt--; } -/* diable the usb interrupt */ +/* disable the usb interrupt */ void fhci_usb_disable_interrupt(struct fhci_usb *usb) { struct fhci_hcd *fhci = usb->fhci; if (usb->intr_nesting_cnt == 0) { - /* diable the timer interrupt */ + /* disable the timer interrupt */ disable_irq_nosync(fhci->timer->irq); /* disable the usb interrupt */ diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index 7be548ca2183..38fe058fbe61 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -271,8 +271,8 @@ void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep, /* * Collect the submitted frames and inform the application about them - * It is also prepearing the TDs for new frames. If the Tx interrupts - * are diabled, the application should call that routine to get + * It is also preparing the TDs for new frames. If the Tx interrupts + * are disabled, the application should call that routine to get * confirmation about the submitted frames. Otherwise, the routine is * called frome the interrupt service routine during the Tx interrupt. * In that case the application is informed by calling the application diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index e49b75a78000..f90d003f2302 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1658,7 +1658,7 @@ static int imx21_hc_reset(struct usb_hcd *hcd) spin_lock_irqsave(&imx21->lock, flags); - /* Reset the Host controler modules */ + /* Reset the Host controller modules */ writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH | USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC, imx21->regs + USBOTG_RST_CTRL); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 32149be4ad8e..e0cb12b573f9 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3094,7 +3094,7 @@ static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf) /* Some boards (mostly VIA?) report bogus overcurrent indications, * causing massive log spam unless we completely ignore them. It - * may be relevant that VIA VT8235 controlers, where PORT_POWER is + * may be relevant that VIA VT8235 controllers, where PORT_POWER is * always set, seem to clear PORT_OCC and PORT_CSC when writing to * PORT_POWER; that's surprising, but maybe within-spec. */ diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 44f8b9225054..a6afd15f6a46 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -717,7 +717,7 @@ static int adu_probe(struct usb_interface *interface, goto exit; } - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "Out of memory\n"); diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index c9078e4e1f4d..e573e4704015 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -769,7 +769,7 @@ static int iowarrior_probe(struct usb_interface *interface, int i; int retval = -ENOMEM; - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "Out of memory\n"); diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index edffef642337..eefb8275bb7e 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -642,7 +642,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * int i; int retval = -ENOMEM; - /* allocate memory for our device state and intialize it */ + /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9b162dfaa4fb..ed58c6c8f15c 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1684,7 +1684,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb) struct musb_hw_ep *hw_ep; unsigned count = 0; - /* intialize endpoint list just once */ + /* initialize endpoint list just once */ INIT_LIST_HEAD(&(musb->g.ep_list)); for (epnum = 0, hw_ep = musb->endpoints; @@ -1765,7 +1765,7 @@ void musb_gadget_cleanup(struct musb *musb) * * -EINVAL something went wrong (not driver) * -EBUSY another gadget is already using the controller - * -ENOMEM no memeory to perform the operation + * -ENOMEM no memory to perform the operation * * @param driver the gadget driver * @param bind the driver's bind function diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index c7b1d8108de9..8cb9d80207fa 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -49,7 +49,7 @@ * * USB Stack port number 4 (1 based) * WUSB code port index 3 (0 based) - * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub) + * USB Address 5 (2 based -- 0 is for default, 1 for root hub) * * Now, because we don't use the concept as default address exactly * like the (wired) USB code does, we need to kind of skip it. So we diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 55dc6fb6e909..d916ac04abab 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -11,6 +11,13 @@ config HAVE_FB_ATMEL config HAVE_FB_IMX bool +config SH_MIPI_DSI + tristate + depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK + +config SH_LCD_MIPI_DSI + bool + source "drivers/char/agp/Kconfig" source "drivers/gpu/vga/Kconfig" @@ -414,7 +421,7 @@ config FB_SA1100 Y here. config FB_IMX - tristate "Motorola i.MX LCD support" + tristate "Freescale i.MX LCD support" depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2) select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -1273,7 +1280,7 @@ config FB_MATROX module will be called matroxfb. You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=matrox:XXX", and + module load time. The parameters look like "video=matroxfb:XXX", and are described in <file:Documentation/fb/matroxfb.txt>. config FB_MATROX_MILLENIUM @@ -1990,13 +1997,6 @@ config FB_W100 If unsure, say N. -config SH_MIPI_DSI - tristate - depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK - -config SH_LCD_MIPI_DSI - bool - config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 8dce25126330..bac163450216 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -111,7 +111,7 @@ static int atmel_bl_get_brightness(struct backlight_device *bl) return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); } -static struct backlight_ops atmel_lcdc_bl_ops = { +static const struct backlight_ops atmel_lcdc_bl_ops = { .update_status = atmel_bl_update_status, .get_brightness = atmel_bl_get_brightness, }; diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 34a0851bcbfa..dd9de2e80580 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1786,7 +1786,7 @@ static int aty128_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops aty128_bl_data = { +static const struct backlight_ops aty128_bl_data = { .get_brightness = aty128_bl_get_brightness, .update_status = aty128_bl_update_status, }; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 5a3ce3ad1ec8..767ab4fb1a05 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2221,7 +2221,7 @@ static int aty_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops aty_bl_data = { +static const struct backlight_ops aty_bl_data = { .get_brightness = aty_bl_get_brightness, .update_status = aty_bl_update_status, }; diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 256966e9667d..9b811ddbce83 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -128,7 +128,7 @@ static int radeon_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops radeon_bl_data = { +static const struct backlight_ops radeon_bl_data = { .get_brightness = radeon_bl_get_brightness, .update_status = radeon_bl_update_status, }; diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 38ffc3fbcbe4..c789c46e38af 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -155,7 +155,7 @@ out: return -EINVAL; } -static struct backlight_ops pm860x_backlight_ops = { +static const struct backlight_ops pm860x_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = pm860x_backlight_update_status, .get_brightness = pm860x_backlight_get_brightness, diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index c67801e57aaf..98ad3e5f7c85 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -25,7 +25,7 @@ struct l4f00242t03_priv { struct spi_device *spi; struct lcd_device *ld; - int lcd_on:1; + int lcd_state; struct regulator *io_reg; struct regulator *core_reg; }; @@ -62,11 +62,36 @@ static void l4f00242t03_lcd_init(struct spi_device *spi) regulator_enable(priv->core_reg); } + l4f00242t03_reset(pdata->reset_gpio); + gpio_set_value(pdata->data_enable_gpio, 1); msleep(60); spi_write(spi, (const u8 *)cmd, ARRAY_SIZE(cmd) * sizeof(u16)); } +static void l4f00242t03_lcd_powerdown(struct spi_device *spi) +{ + struct l4f00242t03_pdata *pdata = spi->dev.platform_data; + struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "Powering down LCD\n"); + + gpio_set_value(pdata->data_enable_gpio, 0); + + if (priv->io_reg) + regulator_disable(priv->io_reg); + + if (priv->core_reg) + regulator_disable(priv->core_reg); +} + +static int l4f00242t03_lcd_power_get(struct lcd_device *ld) +{ + struct l4f00242t03_priv *priv = lcd_get_data(ld); + + return priv->lcd_state; +} + static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) { struct l4f00242t03_priv *priv = lcd_get_data(ld); @@ -79,35 +104,54 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) const u16 disoff = 0x28; if (power <= FB_BLANK_NORMAL) { - if (priv->lcd_on) - return 0; - - dev_dbg(&spi->dev, "turning on LCD\n"); - - spi_write(spi, (const u8 *)&slpout, sizeof(u16)); - msleep(60); - spi_write(spi, (const u8 *)&dison, sizeof(u16)); - - priv->lcd_on = 1; + if (priv->lcd_state <= FB_BLANK_NORMAL) { + /* Do nothing, the LCD is running */ + } else if (priv->lcd_state < FB_BLANK_POWERDOWN) { + dev_dbg(&spi->dev, "Resuming LCD\n"); + + spi_write(spi, (const u8 *)&slpout, sizeof(u16)); + msleep(60); + spi_write(spi, (const u8 *)&dison, sizeof(u16)); + } else { + /* priv->lcd_state == FB_BLANK_POWERDOWN */ + l4f00242t03_lcd_init(spi); + priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; + l4f00242t03_lcd_power_set(priv->ld, power); + } + } else if (power < FB_BLANK_POWERDOWN) { + if (priv->lcd_state <= FB_BLANK_NORMAL) { + /* Send the display in standby */ + dev_dbg(&spi->dev, "Standby the LCD\n"); + + spi_write(spi, (const u8 *)&disoff, sizeof(u16)); + msleep(60); + spi_write(spi, (const u8 *)&slpin, sizeof(u16)); + } else if (priv->lcd_state < FB_BLANK_POWERDOWN) { + /* Do nothing, the LCD is already in standby */ + } else { + /* priv->lcd_state == FB_BLANK_POWERDOWN */ + l4f00242t03_lcd_init(spi); + priv->lcd_state = FB_BLANK_UNBLANK; + l4f00242t03_lcd_power_set(ld, power); + } } else { - if (!priv->lcd_on) - return 0; - - dev_dbg(&spi->dev, "turning off LCD\n"); - - spi_write(spi, (const u8 *)&disoff, sizeof(u16)); - msleep(60); - spi_write(spi, (const u8 *)&slpin, sizeof(u16)); - - priv->lcd_on = 0; + /* power == FB_BLANK_POWERDOWN */ + if (priv->lcd_state != FB_BLANK_POWERDOWN) { + /* Clear the screen before shutting down */ + spi_write(spi, (const u8 *)&disoff, sizeof(u16)); + msleep(60); + l4f00242t03_lcd_powerdown(spi); + } } + priv->lcd_state = power; + return 0; } static struct lcd_ops l4f_ops = { .set_power = l4f00242t03_lcd_power_set, - .get_power = NULL, + .get_power = l4f00242t03_lcd_power_get, }; static int __devinit l4f00242t03_probe(struct spi_device *spi) @@ -185,9 +229,9 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) } /* Init the LCD */ - l4f00242t03_reset(pdata->reset_gpio); l4f00242t03_lcd_init(spi); - l4f00242t03_lcd_power_set(priv->ld, 1); + priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; + l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_UNBLANK); dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n"); @@ -214,9 +258,11 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); struct l4f00242t03_pdata *pdata = priv->spi->dev.platform_data; - l4f00242t03_lcd_power_set(priv->ld, 0); + l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); lcd_device_unregister(priv->ld); + dev_set_drvdata(&spi->dev, NULL); + gpio_free(pdata->data_enable_gpio); gpio_free(pdata->reset_gpio); @@ -230,6 +276,15 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) return 0; } +static void l4f00242t03_shutdown(struct spi_device *spi) +{ + struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); + + if (priv) + l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); + +} + static struct spi_driver l4f00242t03_driver = { .driver = { .name = "l4f00242t03", @@ -237,6 +292,7 @@ static struct spi_driver l4f00242t03_driver = { }, .probe = l4f00242t03_probe, .remove = __devexit_p(l4f00242t03_remove), + .shutdown = l4f00242t03_shutdown, }; static __init int l4f00242t03_init(void) diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index b2b2c7ba1f63..209acc105cbc 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -92,7 +92,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl) return ret; } -static struct backlight_ops max8925_backlight_ops = { +static const struct backlight_ops max8925_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = max8925_backlight_update_status, .get_brightness = max8925_backlight_get_brightness, diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 915448ec75bf..c97491b8b39b 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -375,7 +375,8 @@ static const char *vgacon_startup(void) u16 saved1, saved2; volatile u16 *p; - if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) { + if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB || + screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) { no_vga: #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 1ab2c2588675..69bd4a581d4a 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -974,6 +974,6 @@ static void __exit imxfb_cleanup(void) module_init(imxfb_init); module_exit(imxfb_cleanup); -MODULE_DESCRIPTION("Motorola i.MX framebuffer driver"); +MODULE_DESCRIPTION("Freescale i.MX framebuffer driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 052dd9f0b760..a082debe824b 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1247,46 +1247,46 @@ static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; }; /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ -static unsigned int mem; /* "matrox:mem:xxxxxM" */ +static unsigned int mem; /* "matroxfb:mem:xxxxxM" */ static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ -static int inv24; /* "matrox:inv24" */ -static int cross4MB = -1; /* "matrox:cross4MB" */ -static int disabled; /* "matrox:disabled" */ -static int noaccel; /* "matrox:noaccel" */ -static int nopan; /* "matrox:nopan" */ -static int no_pci_retry; /* "matrox:nopciretry" */ -static int novga; /* "matrox:novga" */ -static int nobios; /* "matrox:nobios" */ -static int noinit = 1; /* "matrox:init" */ -static int inverse; /* "matrox:inverse" */ -static int sgram; /* "matrox:sgram" */ +static int inv24; /* "matroxfb:inv24" */ +static int cross4MB = -1; /* "matroxfb:cross4MB" */ +static int disabled; /* "matroxfb:disabled" */ +static int noaccel; /* "matroxfb:noaccel" */ +static int nopan; /* "matroxfb:nopan" */ +static int no_pci_retry; /* "matroxfb:nopciretry" */ +static int novga; /* "matroxfb:novga" */ +static int nobios; /* "matroxfb:nobios" */ +static int noinit = 1; /* "matroxfb:init" */ +static int inverse; /* "matroxfb:inverse" */ +static int sgram; /* "matroxfb:sgram" */ #ifdef CONFIG_MTRR -static int mtrr = 1; /* "matrox:nomtrr" */ +static int mtrr = 1; /* "matroxfb:nomtrr" */ #endif -static int grayscale; /* "matrox:grayscale" */ -static int dev = -1; /* "matrox:dev:xxxxx" */ -static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ -static int depth = -1; /* "matrox:depth:xxxxx" */ -static unsigned int xres; /* "matrox:xres:xxxxx" */ -static unsigned int yres; /* "matrox:yres:xxxxx" */ -static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */ -static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */ -static unsigned int vslen; /* "matrox:vslen:xxxxx" */ -static unsigned int left = ~0; /* "matrox:left:xxxxx" */ -static unsigned int right = ~0; /* "matrox:right:xxxxx" */ -static unsigned int hslen; /* "matrox:hslen:xxxxx" */ -static unsigned int pixclock; /* "matrox:pixclock:xxxxx" */ -static int sync = -1; /* "matrox:sync:xxxxx" */ -static unsigned int fv; /* "matrox:fv:xxxxx" */ -static unsigned int fh; /* "matrox:fh:xxxxxk" */ -static unsigned int maxclk; /* "matrox:maxclk:xxxxM" */ -static int dfp; /* "matrox:dfp */ -static int dfp_type = -1; /* "matrox:dfp:xxx */ -static int memtype = -1; /* "matrox:memtype:xxx" */ -static char outputs[8]; /* "matrox:outputs:xxx" */ +static int grayscale; /* "matroxfb:grayscale" */ +static int dev = -1; /* "matroxfb:dev:xxxxx" */ +static unsigned int vesa = ~0; /* "matroxfb:vesa:xxxxx" */ +static int depth = -1; /* "matroxfb:depth:xxxxx" */ +static unsigned int xres; /* "matroxfb:xres:xxxxx" */ +static unsigned int yres; /* "matroxfb:yres:xxxxx" */ +static unsigned int upper = ~0; /* "matroxfb:upper:xxxxx" */ +static unsigned int lower = ~0; /* "matroxfb:lower:xxxxx" */ +static unsigned int vslen; /* "matroxfb:vslen:xxxxx" */ +static unsigned int left = ~0; /* "matroxfb:left:xxxxx" */ +static unsigned int right = ~0; /* "matroxfb:right:xxxxx" */ +static unsigned int hslen; /* "matroxfb:hslen:xxxxx" */ +static unsigned int pixclock; /* "matroxfb:pixclock:xxxxx" */ +static int sync = -1; /* "matroxfb:sync:xxxxx" */ +static unsigned int fv; /* "matroxfb:fv:xxxxx" */ +static unsigned int fh; /* "matroxfb:fh:xxxxxk" */ +static unsigned int maxclk; /* "matroxfb:maxclk:xxxxM" */ +static int dfp; /* "matroxfb:dfp */ +static int dfp_type = -1; /* "matroxfb:dfp:xxx */ +static int memtype = -1; /* "matroxfb:memtype:xxx" */ +static char outputs[8]; /* "matroxfb:outputs:xxx" */ #ifndef MODULE -static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ +static char videomode[64]; /* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */ #endif static int matroxfb_getmemory(struct matrox_fb_info *minfo, diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index d2bb365f09b3..48c3ea8652b6 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -32,300 +32,320 @@ const char *fb_mode_option; EXPORT_SYMBOL_GPL(fb_mode_option); - /* - * Standard video mode definitions (taken from XFree86) - */ +/* + * Standard video mode definitions (taken from XFree86) + */ static const struct fb_videomode modedb[] = { - { + /* 640x400 @ 70 Hz, 31.5 kHz hsync */ - NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ - NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, + FB_VMODE_NONINTERLACED }, + /* 800x600 @ 56 Hz, 35.15 kHz hsync */ - NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ - NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, 0, + FB_VMODE_INTERLACED }, + /* 640x400 @ 85 Hz, 37.86 kHz hsync */ - NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + /* 640x480 @ 72 Hz, 36.5 kHz hsync */ - NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 75 Hz, 37.50 kHz hsync */ - NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 800x600 @ 60 Hz, 37.8 kHz hsync */ - NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 85 Hz, 43.27 kHz hsync */ - NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ - NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, 0, + FB_VMODE_INTERLACED }, /* 800x600 @ 72 Hz, 48.0 kHz hsync */ - NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ - NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 640x480 @ 100 Hz, 53.01 kHz hsync */ - NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ - NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, 0, + FB_VMODE_NONINTERLACED }, + /* 800x600 @ 85 Hz, 55.84 kHz hsync */ - NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ - NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ - NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, 0, + FB_VMODE_INTERLACED }, + /* 800x600 @ 100 Hz, 64.02 kHz hsync */ - NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ - NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ - NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ - NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ - NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ - NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ - NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ - NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ - NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ - NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, 0, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ - NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ - NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ - NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1024x768 @ 100Hz, 80.21 kHz hsync */ - NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ - NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ - NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ - NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ - NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ - NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */ - NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ - NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ - NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, 0, + FB_VMODE_NONINTERLACED }, + /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ - NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ - NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 512x384 @ 78 Hz, 31.50 kHz hsync */ - NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 512x384 @ 85 Hz, 34.38 kHz hsync */ - NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, 0, + FB_VMODE_NONINTERLACED }, + /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ - NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, 0, + FB_VMODE_DOUBLE }, + /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ - NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, 0, + FB_VMODE_DOUBLE }, + /* 320x240 @ 72 Hz, 36.5 kHz hsync */ - NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, 0, + FB_VMODE_DOUBLE }, + /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ - NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, 0, + FB_VMODE_DOUBLE }, + /* 400x300 @ 60 Hz, 37.8 kHz hsync */ - NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, 0, + FB_VMODE_DOUBLE }, + /* 400x300 @ 72 Hz, 48.0 kHz hsync */ - NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ - NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 60 Hz, 37.8 kHz hsync */ - NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 63 Hz, 39.6 kHz hsync */ - NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, 0, + FB_VMODE_DOUBLE }, + /* 480x300 @ 72 Hz, 48.0 kHz hsync */ - NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, - 0, FB_VMODE_DOUBLE - }, { + { NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, 0, + FB_VMODE_DOUBLE }, + /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */ - NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ - NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED }, + /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ - NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, - 0, FB_VMODE_NONINTERLACED - }, { + { NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, 0, + FB_VMODE_NONINTERLACED }, + /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ - NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, - 0, FB_VMODE_NONINTERLACED - }, { - /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ - NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, - 0, FB_VMODE_INTERLACED - }, { - /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ - NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, - 0, FB_VMODE_INTERLACED - }, { + { NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 0, + FB_VMODE_NONINTERLACED }, + + /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + { NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5, 0, + FB_VMODE_INTERLACED }, + + /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */ + { NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5, 0, + FB_VMODE_INTERLACED }, + /* 864x480 @ 60 Hz, 35.15 kHz hsync */ - NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0, - 0, FB_VMODE_NONINTERLACED - }, + { NULL, 60, 864, 480, 27777, 1, 1, 1, 1, 0, 0, + 0, FB_VMODE_NONINTERLACED }, }; #ifdef CONFIG_FB_MODE_HELPERS const struct fb_videomode cea_modes[64] = { /* #1: 640x480p@59.94/60Hz */ [1] = { - NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #3: 720x480p@59.94/60Hz */ [3] = { - NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #5: 1920x1080i@59.94/60Hz */ [5] = { NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, 0, }, /* #7: 720(1440)x480iH@59.94/60Hz */ [7] = { - NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, FB_VMODE_INTERLACED, 0, + NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, + FB_VMODE_INTERLACED, 0, }, /* #9: 720(1440)x240pH@59.94/60Hz */ [9] = { - NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #18: 720x576pH@50Hz */ [18] = { - NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, + FB_VMODE_NONINTERLACED, 0, }, /* #19: 1280x720p@50Hz */ [19] = { NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0, }, /* #20: 1920x1080i@50Hz */ [20] = { NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, 0, }, /* #32: 1920x1080p@23.98/24Hz */ [32] = { NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 0, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, 0, }, /* #35: (2880)x480p4x@59.94/60Hz */ [35] = { - NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0, FB_VMODE_NONINTERLACED, 0, + NULL, 60, 2880, 480, 9250, 240, 64, 30, 9, 248, 6, 0, + FB_VMODE_NONINTERLACED, 0, }, }; @@ -340,10 +360,10 @@ const struct fb_videomode vesa_modes[] = { { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 3 640x480-60 VESA */ - { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, + { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 4 640x480-72 VESA */ - { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, + { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 5 640x480-75 VESA */ { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, @@ -426,7 +446,7 @@ const struct fb_videomode vesa_modes[] = { FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 26 1600x1200-75 VESA */ - { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, + { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 27 1600x1200-85 VESA */ diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 81687ed26ba9..62498bd662fc 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -15,6 +15,7 @@ */ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> @@ -597,9 +598,9 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev) } fbi->clk = clk_get(&pdev->dev, NULL); - if (!fbi->clk || IS_ERR(fbi->clk)) { + if (IS_ERR(fbi->clk)) { printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n"); - ret = -ENOENT; + ret = PTR_ERR(fbi->clk); goto release_irq; } diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 2fb552a6f32c..6aac6d1b937b 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -87,7 +87,7 @@ static int nvidia_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops nvidia_bl_ops = { +static const struct backlight_ops nvidia_bl_ops = { .get_brightness = nvidia_bl_get_brightness, .update_status = nvidia_bl_update_status, }; diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 12327bbfdbbb..940cab394c2e 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -1,11 +1,13 @@ menu "OMAP2/3 Display Device Drivers" depends on OMAP2_DSS -config PANEL_GENERIC - tristate "Generic Panel" +config PANEL_GENERIC_DPI + tristate "Generic DPI Panel" help - Generic panel driver. - Used for DVI output for Beagle and OMAP3 SDP. + Generic DPI panel driver. + Supports DVI output for Beagle and OMAP3 SDP. + Supports LCD Panel used in TI SDP3430 and EVM boards, + OMAP3517 EVM boards and CM-T35. config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" @@ -14,11 +16,12 @@ config PANEL_SHARP_LS037V7DW01 help LCD Panel used in TI's SDP3430 and EVM boards -config PANEL_SHARP_LQ043T1DG01 - tristate "Sharp LQ043T1DG01 LCD Panel" - depends on OMAP2_DSS - help - LCD Panel used in TI's OMAP3517 EVM boards +config PANEL_NEC_NL8048HL11_01B + tristate "NEC NL8048HL11-01B Panel" + depends on OMAP2_DSS + help + This NEC NL8048HL11-01B panel is TFT LCD + used in the Zoom2/3/3630 sdp boards. config PANEL_TAAL tristate "Taal DSI Panel" @@ -26,12 +29,6 @@ config PANEL_TAAL help Taal DSI command mode panel from TPO. -config PANEL_TOPPOLY_TDO35S - tristate "Toppoly TDO35S LCD Panel support" - depends on OMAP2_DSS - help - LCD Panel used in CM-T35 - config PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" depends on OMAP2_DSS && SPI diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index aa386095d7c4..861f0255ec6b 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -1,8 +1,7 @@ -obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o +obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o -obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o +obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o obj-$(CONFIG_PANEL_TAAL) += panel-taal.o -obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c new file mode 100644 index 000000000000..07eb30ee59c8 --- /dev/null +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -0,0 +1,365 @@ +/* + * Generic DPI Panels support + * + * Copyright (C) 2010 Canonical Ltd. + * Author: Bryan Wu <bryan.wu@canonical.com> + * + * LCD panel driver for Sharp LQ043T1DG01 + * + * Copyright (C) 2009 Texas Instruments Inc + * Author: Vaibhav Hiremath <hvaibhav@ti.com> + * + * LCD panel driver for Toppoly TDO35S + * + * Copyright (C) 2009 CompuLab, Ltd. + * Author: Mike Rapoport <mike@compulab.co.il> + * + * Copyright (C) 2008 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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/module.h> +#include <linux/delay.h> +#include <linux/slab.h> + +#include <plat/panel-generic-dpi.h> + +struct panel_config { + struct omap_video_timings timings; + + int acbi; /* ac-bias pin transitions per interrupt */ + /* Unit: line clocks */ + int acb; /* ac-bias pin frequency */ + + enum omap_panel_config config; + + int power_on_delay; + int power_off_delay; + + /* + * Used to match device to panel configuration + * when use generic panel driver + */ + const char *name; +}; + +/* Panel configurations */ +static struct panel_config generic_dpi_panels[] = { + /* Generic Panel */ + { + { + .x_res = 640, + .y_res = 480, + + .pixel_clock = 23500, + + .hfp = 48, + .hsw = 32, + .hbp = 80, + + .vfp = 3, + .vsw = 4, + .vbp = 7, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "generic", + }, + + /* Sharp LQ043T1DG01 */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 9000, + + .hsw = 42, + .hfp = 3, + .hbp = 2, + + .vsw = 11, + .vfp = 3, + .vbp = 2, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, + .power_on_delay = 50, + .power_off_delay = 100, + .name = "sharp_lq", + }, + + /* Sharp LS037V7DW01 */ + { + { + .x_res = 480, + .y_res = 640, + + .pixel_clock = 19200, + + .hsw = 2, + .hfp = 1, + .hbp = 28, + + .vsw = 1, + .vfp = 1, + .vbp = 1, + }, + .acbi = 0x0, + .acb = 0x28, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .power_on_delay = 50, + .power_off_delay = 100, + .name = "sharp_ls", + }, + + /* Toppoly TDO35S */ + { + { + .x_res = 480, + .y_res = 640, + + .pixel_clock = 26000, + + .hfp = 104, + .hsw = 8, + .hbp = 8, + + .vfp = 4, + .vsw = 2, + .vbp = 2, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC | + OMAP_DSS_LCD_ONOFF, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "toppoly_tdo35s", + }, +}; + +struct panel_drv_data { + + struct omap_dss_device *dssdev; + + struct panel_config *panel_config; +}; + +static inline struct panel_generic_dpi_data +*get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct panel_generic_dpi_data *) dssdev->data; +} + +static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) +{ + int r; + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + struct panel_config *panel_config = drv_data->panel_config; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + + /* wait couple of vsyncs until enabling the LCD */ + if (panel_config->power_on_delay) + msleep(panel_config->power_on_delay); + + if (panel_data->platform_enable) { + r = panel_data->platform_enable(dssdev); + if (r) + goto err1; + } + + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: + return r; +} + +static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) +{ + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + struct panel_config *panel_config = drv_data->panel_config; + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; + + if (panel_data->platform_disable) + panel_data->platform_disable(dssdev); + + /* wait couple of vsyncs after disabling the LCD */ + if (panel_config->power_off_delay) + msleep(panel_config->power_off_delay); + + omapdss_dpi_display_disable(dssdev); +} + +static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) +{ + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + struct panel_config *panel_config = NULL; + struct panel_drv_data *drv_data = NULL; + int i; + + dev_dbg(&dssdev->dev, "probe\n"); + + if (!panel_data || !panel_data->name) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) { + if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) { + panel_config = &generic_dpi_panels[i]; + break; + } + } + + if (!panel_config) + return -EINVAL; + + dssdev->panel.config = panel_config->config; + dssdev->panel.timings = panel_config->timings; + dssdev->panel.acb = panel_config->acb; + dssdev->panel.acbi = panel_config->acbi; + + drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + drv_data->dssdev = dssdev; + drv_data->panel_config = panel_config; + + dev_set_drvdata(&dssdev->dev, drv_data); + + return 0; +} + +static void generic_dpi_panel_remove(struct omap_dss_device *dssdev) +{ + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + dev_dbg(&dssdev->dev, "remove\n"); + + kfree(drv_data); + + dev_set_drvdata(&dssdev->dev, NULL); +} + +static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + r = generic_dpi_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) +{ + generic_dpi_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +} + +static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) +{ + generic_dpi_panel_power_off(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + + return 0; +} + +static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) +{ + int r = 0; + + r = generic_dpi_panel_power_on(dssdev); + if (r) + return r; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + return 0; +} + +static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dpi_set_timings(dssdev, timings); +} + +static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + *timings = dssdev->panel.timings; +} + +static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + return dpi_check_timings(dssdev, timings); +} + +static struct omap_dss_driver dpi_driver = { + .probe = generic_dpi_panel_probe, + .remove = generic_dpi_panel_remove, + + .enable = generic_dpi_panel_enable, + .disable = generic_dpi_panel_disable, + .suspend = generic_dpi_panel_suspend, + .resume = generic_dpi_panel_resume, + + .set_timings = generic_dpi_panel_set_timings, + .get_timings = generic_dpi_panel_get_timings, + .check_timings = generic_dpi_panel_check_timings, + + .driver = { + .name = "generic_dpi_panel", + .owner = THIS_MODULE, + }, +}; + +static int __init generic_dpi_panel_drv_init(void) +{ + return omap_dss_register_driver(&dpi_driver); +} + +static void __exit generic_dpi_panel_drv_exit(void) +{ + omap_dss_unregister_driver(&dpi_driver); +} + +module_init(generic_dpi_panel_drv_init); +module_exit(generic_dpi_panel_drv_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c deleted file mode 100644 index 395a68de3990..000000000000 --- a/drivers/video/omap2/displays/panel-generic.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Generic panel support - * - * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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/module.h> -#include <linux/delay.h> - -#include <plat/display.h> - -static struct omap_video_timings generic_panel_timings = { - /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ - .x_res = 640, - .y_res = 480, - .pixel_clock = 23500, - .hfp = 48, - .hsw = 32, - .hbp = 80, - .vfp = 3, - .vsw = 4, - .vbp = 7, -}; - -static int generic_panel_power_on(struct omap_dss_device *dssdev) -{ - int r; - - 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) - goto err1; - } - - return 0; -err1: - omapdss_dpi_display_disable(dssdev); -err0: - return r; -} - -static void generic_panel_power_off(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return; - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - omapdss_dpi_display_disable(dssdev); -} - -static int generic_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.config = OMAP_DSS_LCD_TFT; - dssdev->panel.timings = generic_panel_timings; - - return 0; -} - -static void generic_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int generic_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = generic_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void generic_panel_disable(struct omap_dss_device *dssdev) -{ - generic_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} - -static int generic_panel_suspend(struct omap_dss_device *dssdev) -{ - generic_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int generic_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = generic_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void generic_panel_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - dpi_set_timings(dssdev, timings); -} - -static void generic_panel_get_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - *timings = dssdev->panel.timings; -} - -static int generic_panel_check_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) -{ - return dpi_check_timings(dssdev, timings); -} - -static struct omap_dss_driver generic_driver = { - .probe = generic_panel_probe, - .remove = generic_panel_remove, - - .enable = generic_panel_enable, - .disable = generic_panel_disable, - .suspend = generic_panel_suspend, - .resume = generic_panel_resume, - - .set_timings = generic_panel_set_timings, - .get_timings = generic_panel_get_timings, - .check_timings = generic_panel_check_timings, - - .driver = { - .name = "generic_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init generic_panel_drv_init(void) -{ - return omap_dss_register_driver(&generic_driver); -} - -static void __exit generic_panel_drv_exit(void) -{ - omap_dss_unregister_driver(&generic_driver); -} - -module_init(generic_panel_drv_init); -module_exit(generic_panel_drv_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c new file mode 100644 index 000000000000..925e0fadff54 --- /dev/null +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -0,0 +1,325 @@ +/* + * Support for NEC-nl8048hl11-01b panel driver + * + * Copyright (C) 2010 Texas Instruments Inc. + * Author: Erik Gilling <konkers@android.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/module.h> +#include <linux/delay.h> +#include <linux/spi/spi.h> +#include <linux/backlight.h> +#include <linux/fb.h> + +#include <plat/display.h> + +#define LCD_XRES 800 +#define LCD_YRES 480 +/* + * NEC PIX Clock Ratings + * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz + */ +#define LCD_PIXEL_CLOCK 23800 + +struct nec_8048_data { + struct backlight_device *bl; +}; + +static const struct { + unsigned char addr; + unsigned char dat; +} nec_8048_init_seq[] = { + { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 }, + { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 }, + { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 }, + { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F }, + { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F }, + { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F }, + { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F }, + { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 }, + { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 }, + { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C }, + { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 }, + { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 }, + { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 }, + { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 }, + { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC }, + { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 }, + { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 }, + { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 }, +}; + +/* + * NEC NL8048HL11-01B Manual + * defines HFB, HSW, HBP, VFP, VSW, VBP as shown below + */ + +static struct omap_video_timings nec_8048_panel_timings = { + /* 800 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ + .x_res = LCD_XRES, + .y_res = LCD_YRES, + .pixel_clock = LCD_PIXEL_CLOCK, + .hfp = 6, + .hsw = 1, + .hbp = 4, + .vfp = 3, + .vsw = 1, + .vbp = 4, +}; + +static int nec_8048_bl_update_status(struct backlight_device *bl) +{ + struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); + int level; + + if (!dssdev->set_backlight) + return -EINVAL; + + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + level = bl->props.brightness; + else + level = 0; + + return dssdev->set_backlight(dssdev, level); +} + +static int nec_8048_bl_get_brightness(struct backlight_device *bl) +{ + if (bl->props.fb_blank == FB_BLANK_UNBLANK && + bl->props.power == FB_BLANK_UNBLANK) + return bl->props.brightness; + + return 0; +} + +static const struct backlight_ops nec_8048_bl_ops = { + .get_brightness = nec_8048_bl_get_brightness, + .update_status = nec_8048_bl_update_status, +}; + +static int nec_8048_panel_probe(struct omap_dss_device *dssdev) +{ + struct backlight_device *bl; + struct nec_8048_data *necd; + struct backlight_properties props; + int r; + + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF | + OMAP_DSS_LCD_ONOFF; + dssdev->panel.timings = nec_8048_panel_timings; + + necd = kzalloc(sizeof(*necd), GFP_KERNEL); + if (!necd) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, necd); + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 255; + + bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev, + &nec_8048_bl_ops, &props); + if (IS_ERR(bl)) { + r = PTR_ERR(bl); + kfree(necd); + return r; + } + necd->bl = bl; + + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.power = FB_BLANK_UNBLANK; + bl->props.max_brightness = dssdev->max_backlight_level; + bl->props.brightness = dssdev->max_backlight_level; + + r = nec_8048_bl_update_status(bl); + if (r < 0) + dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + + return 0; +} + +static void nec_8048_panel_remove(struct omap_dss_device *dssdev) +{ + struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = necd->bl; + + bl->props.power = FB_BLANK_POWERDOWN; + nec_8048_bl_update_status(bl); + backlight_device_unregister(bl); + + kfree(necd); +} + +static int nec_8048_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); + struct backlight_device *bl = necd->bl; + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + return r; + } + + 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 r; +} + +static void nec_8048_panel_disable(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); + + bl->props.brightness = 0; + nec_8048_bl_update_status(bl); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +} + +static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) +{ + nec_8048_panel_disable(dssdev); + return 0; +} + +static int nec_8048_panel_resume(struct omap_dss_device *dssdev) +{ + return nec_8048_panel_enable(dssdev); +} + +static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) +{ + return 16; +} + +static struct omap_dss_driver nec_8048_driver = { + .probe = nec_8048_panel_probe, + .remove = nec_8048_panel_remove, + .enable = nec_8048_panel_enable, + .disable = nec_8048_panel_disable, + .suspend = nec_8048_panel_suspend, + .resume = nec_8048_panel_resume, + .get_recommended_bpp = nec_8048_recommended_bpp, + + .driver = { + .name = "NEC_8048_panel", + .owner = THIS_MODULE, + }, +}; + +static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr, + unsigned char reg_data) +{ + int ret = 0; + unsigned int cmd = 0, data = 0; + + cmd = 0x0000 | reg_addr; /* register address write */ + data = 0x0100 | reg_data ; /* register data write */ + data = (cmd << 16) | data; + + ret = spi_write(spi, (unsigned char *)&data, 4); + if (ret) + pr_err("error in spi_write %x\n", data); + + return ret; +} + +static int init_nec_8048_wvga_lcd(struct spi_device *spi) +{ + unsigned int i; + /* Initialization Sequence */ + /* nec_8048_spi_send(spi, REG, VAL) */ + for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++) + nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, + nec_8048_init_seq[i].dat); + udelay(20); + nec_8048_spi_send(spi, nec_8048_init_seq[i].addr, + nec_8048_init_seq[i].dat); + return 0; +} + +static int nec_8048_spi_probe(struct spi_device *spi) +{ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 32; + spi_setup(spi); + + init_nec_8048_wvga_lcd(spi); + + return omap_dss_register_driver(&nec_8048_driver); +} + +static int nec_8048_spi_remove(struct spi_device *spi) +{ + omap_dss_unregister_driver(&nec_8048_driver); + + return 0; +} + +static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg) +{ + nec_8048_spi_send(spi, 2, 0x01); + mdelay(40); + + return 0; +} + +static int nec_8048_spi_resume(struct spi_device *spi) +{ + /* reinitialize the panel */ + spi_setup(spi); + nec_8048_spi_send(spi, 2, 0x00); + init_nec_8048_wvga_lcd(spi); + + return 0; +} + +static struct spi_driver nec_8048_spi_driver = { + .probe = nec_8048_spi_probe, + .remove = __devexit_p(nec_8048_spi_remove), + .suspend = nec_8048_spi_suspend, + .resume = nec_8048_spi_resume, + .driver = { + .name = "nec_8048_spi", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, +}; + +static int __init nec_8048_lcd_init(void) +{ + return spi_register_driver(&nec_8048_spi_driver); +} + +static void __exit nec_8048_lcd_exit(void) +{ + return spi_unregister_driver(&nec_8048_spi_driver); +} + +module_init(nec_8048_lcd_init); +module_exit(nec_8048_lcd_exit); +MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); +MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c b/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c deleted file mode 100644 index 0c6896cea2d0..000000000000 --- a/drivers/video/omap2/displays/panel-sharp-lq043t1dg01.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * LCD panel driver for Sharp LQ043T1DG01 - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Vaibhav Hiremath <hvaibhav@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/module.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/err.h> - -#include <plat/display.h> - -static struct omap_video_timings sharp_lq_timings = { - .x_res = 480, - .y_res = 272, - - .pixel_clock = 9000, - - .hsw = 42, - .hfp = 3, - .hbp = 2, - - .vsw = 11, - .vfp = 3, - .vbp = 2, -}; - -static int sharp_lq_panel_power_on(struct omap_dss_device *dssdev) -{ - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - return 0; - - r = omapdss_dpi_display_enable(dssdev); - if (r) - goto err0; - - /* wait couple of vsyncs until enabling the LCD */ - msleep(50); - - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } - - return 0; -err1: - omapdss_dpi_display_disable(dssdev); -err0: - return r; -} - -static void sharp_lq_panel_power_off(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return; - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - /* wait at least 5 vsyncs after disabling the LCD */ - msleep(100); - - omapdss_dpi_display_disable(dssdev); -} - -static int sharp_lq_panel_probe(struct omap_dss_device *dssdev) -{ - - dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | - OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO; - dssdev->panel.acb = 0x0; - dssdev->panel.timings = sharp_lq_timings; - - return 0; -} - -static void sharp_lq_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int sharp_lq_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = sharp_lq_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void sharp_lq_panel_disable(struct omap_dss_device *dssdev) -{ - sharp_lq_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} - -static int sharp_lq_panel_suspend(struct omap_dss_device *dssdev) -{ - sharp_lq_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int sharp_lq_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = sharp_lq_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static struct omap_dss_driver sharp_lq_driver = { - .probe = sharp_lq_panel_probe, - .remove = sharp_lq_panel_remove, - - .enable = sharp_lq_panel_enable, - .disable = sharp_lq_panel_disable, - .suspend = sharp_lq_panel_suspend, - .resume = sharp_lq_panel_resume, - - .driver = { - .name = "sharp_lq_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init sharp_lq_panel_drv_init(void) -{ - return omap_dss_register_driver(&sharp_lq_driver); -} - -static void __exit sharp_lq_panel_drv_exit(void) -{ - omap_dss_unregister_driver(&sharp_lq_driver); -} - -module_init(sharp_lq_panel_drv_init); -module_exit(sharp_lq_panel_drv_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index e1c765d11419..61026f96ad20 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -465,7 +465,7 @@ static int taal_bl_get_intensity(struct backlight_device *dev) return 0; } -static struct backlight_ops taal_bl_ops = { +static const struct backlight_ops taal_bl_ops = { .get_brightness = taal_bl_get_intensity, .update_status = taal_bl_update_status, }; diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c deleted file mode 100644 index 526e906c8a6c..000000000000 --- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * LCD panel driver for Toppoly TDO35S - * - * Copyright (C) 2009 CompuLab, Ltd. - * Author: Mike Rapoport <mike@compulab.co.il> - * - * Based on generic panel support - * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.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/module.h> -#include <linux/delay.h> - -#include <plat/display.h> - -static struct omap_video_timings toppoly_tdo_panel_timings = { - /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */ - .x_res = 480, - .y_res = 640, - - .pixel_clock = 26000, - - .hfp = 104, - .hsw = 8, - .hbp = 8, - - .vfp = 4, - .vsw = 2, - .vbp = 2, -}; - -static int toppoly_tdo_panel_power_on(struct omap_dss_device *dssdev) -{ - int r; - - 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) - goto err1; - } - - return 0; -err1: - omapdss_dpi_display_disable(dssdev); -err0: - return r; -} - -static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev) -{ - if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) - return; - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - omapdss_dpi_display_disable(dssdev); -} - -static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.config = OMAP_DSS_LCD_TFT | - OMAP_DSS_LCD_IVS | - OMAP_DSS_LCD_IHS | - OMAP_DSS_LCD_IPC | - OMAP_DSS_LCD_ONOFF; - - dssdev->panel.timings = toppoly_tdo_panel_timings; - - return 0; -} - -static void toppoly_tdo_panel_remove(struct omap_dss_device *dssdev) -{ -} - -static int toppoly_tdo_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = toppoly_tdo_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static void toppoly_tdo_panel_disable(struct omap_dss_device *dssdev) -{ - toppoly_tdo_panel_power_off(dssdev); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; -} - -static int toppoly_tdo_panel_suspend(struct omap_dss_device *dssdev) -{ - toppoly_tdo_panel_power_off(dssdev); - dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; - return 0; -} - -static int toppoly_tdo_panel_resume(struct omap_dss_device *dssdev) -{ - int r = 0; - - r = toppoly_tdo_panel_power_on(dssdev); - if (r) - return r; - - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - - return 0; -} - -static struct omap_dss_driver generic_driver = { - .probe = toppoly_tdo_panel_probe, - .remove = toppoly_tdo_panel_remove, - - .enable = toppoly_tdo_panel_enable, - .disable = toppoly_tdo_panel_disable, - .suspend = toppoly_tdo_panel_suspend, - .resume = toppoly_tdo_panel_resume, - - .driver = { - .name = "toppoly_tdo35s_panel", - .owner = THIS_MODULE, - }, -}; - -static int __init toppoly_tdo_panel_drv_init(void) -{ - return omap_dss_register_driver(&generic_driver); -} - -static void __exit toppoly_tdo_panel_drv_exit(void) -{ - omap_dss_unregister_driver(&generic_driver); -} - -module_init(toppoly_tdo_panel_drv_init); -module_exit(toppoly_tdo_panel_drv_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index fa40fa59a9ac..9f8c69f16e61 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -44,34 +44,40 @@ /* DISPC */ #define DISPC_BASE 0x48050400 -#define DISPC_SZ_REGS SZ_1K +#define DISPC_SZ_REGS SZ_4K struct dispc_reg { u16 idx; }; #define DISPC_REG(idx) ((const struct dispc_reg) { idx }) -/* DISPC common */ +/* + * DISPC common registers and + * DISPC channel registers , ch = 0 for LCD, ch = 1 for + * DIGIT, and ch = 2 for LCD2 + */ #define DISPC_REVISION DISPC_REG(0x0000) #define DISPC_SYSCONFIG DISPC_REG(0x0010) #define DISPC_SYSSTATUS DISPC_REG(0x0014) #define DISPC_IRQSTATUS DISPC_REG(0x0018) #define DISPC_IRQENABLE DISPC_REG(0x001C) #define DISPC_CONTROL DISPC_REG(0x0040) +#define DISPC_CONTROL2 DISPC_REG(0x0238) #define DISPC_CONFIG DISPC_REG(0x0044) +#define DISPC_CONFIG2 DISPC_REG(0x0620) #define DISPC_CAPABLE DISPC_REG(0x0048) -#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C) -#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050) -#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054) -#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058) +#define DISPC_DEFAULT_COLOR(ch) DISPC_REG(ch == 0 ? 0x004C : \ + (ch == 1 ? 0x0050 : 0x03AC)) +#define DISPC_TRANS_COLOR(ch) DISPC_REG(ch == 0 ? 0x0054 : \ + (ch == 1 ? 0x0058 : 0x03B0)) #define DISPC_LINE_STATUS DISPC_REG(0x005C) #define DISPC_LINE_NUMBER DISPC_REG(0x0060) -#define DISPC_TIMING_H DISPC_REG(0x0064) -#define DISPC_TIMING_V DISPC_REG(0x0068) -#define DISPC_POL_FREQ DISPC_REG(0x006C) -#define DISPC_DIVISOR DISPC_REG(0x0070) +#define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400) +#define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404) +#define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408) +#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) #define DISPC_SIZE_DIG DISPC_REG(0x0078) -#define DISPC_SIZE_LCD DISPC_REG(0x007C) +#define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC) /* DISPC GFX plane */ #define DISPC_GFX_BA0 DISPC_REG(0x0080) @@ -86,13 +92,12 @@ struct dispc_reg { u16 idx; }; #define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4) #define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8) -#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4) -#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8) -#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC) - -#define DISPC_CPR_COEF_R DISPC_REG(0x0220) -#define DISPC_CPR_COEF_G DISPC_REG(0x0224) -#define DISPC_CPR_COEF_B DISPC_REG(0x0228) +#define DISPC_DATA_CYCLE1(ch) DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0) +#define DISPC_DATA_CYCLE2(ch) DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4) +#define DISPC_DATA_CYCLE3(ch) DISPC_REG(ch != 2 ? 0x01DC : 0x03C8) +#define DISPC_CPR_COEF_R(ch) DISPC_REG(ch != 2 ? 0x0220 : 0x03BC) +#define DISPC_CPR_COEF_G(ch) DISPC_REG(ch != 2 ? 0x0224 : 0x03B8) +#define DISPC_CPR_COEF_B(ch) DISPC_REG(ch != 2 ? 0x0228 : 0x03B4) #define DISPC_GFX_PRELOAD DISPC_REG(0x022C) @@ -217,18 +222,29 @@ void dispc_save_context(void) SR(IRQENABLE); SR(CONTROL); SR(CONFIG); - SR(DEFAULT_COLOR0); - SR(DEFAULT_COLOR1); - SR(TRANS_COLOR0); - SR(TRANS_COLOR1); + SR(DEFAULT_COLOR(0)); + SR(DEFAULT_COLOR(1)); + SR(TRANS_COLOR(0)); + SR(TRANS_COLOR(1)); SR(LINE_NUMBER); - SR(TIMING_H); - SR(TIMING_V); - SR(POL_FREQ); - SR(DIVISOR); + SR(TIMING_H(0)); + SR(TIMING_V(0)); + SR(POL_FREQ(0)); + SR(DIVISOR(0)); SR(GLOBAL_ALPHA); SR(SIZE_DIG); - SR(SIZE_LCD); + SR(SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + SR(CONTROL2); + SR(DEFAULT_COLOR(2)); + SR(TRANS_COLOR(2)); + SR(SIZE_LCD(2)); + SR(TIMING_H(2)); + SR(TIMING_V(2)); + SR(POL_FREQ(2)); + SR(DIVISOR(2)); + SR(CONFIG2); + } SR(GFX_BA0); SR(GFX_BA1); @@ -241,13 +257,22 @@ void dispc_save_context(void) SR(GFX_WINDOW_SKIP); SR(GFX_TABLE_BA); - SR(DATA_CYCLE1); - SR(DATA_CYCLE2); - SR(DATA_CYCLE3); - - SR(CPR_COEF_R); - SR(CPR_COEF_G); - SR(CPR_COEF_B); + SR(DATA_CYCLE1(0)); + SR(DATA_CYCLE2(0)); + SR(DATA_CYCLE3(0)); + + SR(CPR_COEF_R(0)); + SR(CPR_COEF_G(0)); + SR(CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + SR(CPR_COEF_B(2)); + SR(CPR_COEF_G(2)); + SR(CPR_COEF_R(2)); + + SR(DATA_CYCLE1(2)); + SR(DATA_CYCLE2(2)); + SR(DATA_CYCLE3(2)); + } SR(GFX_PRELOAD); @@ -356,18 +381,28 @@ void dispc_restore_context(void) /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); - RR(DEFAULT_COLOR0); - RR(DEFAULT_COLOR1); - RR(TRANS_COLOR0); - RR(TRANS_COLOR1); + RR(DEFAULT_COLOR(0)); + RR(DEFAULT_COLOR(1)); + RR(TRANS_COLOR(0)); + RR(TRANS_COLOR(1)); RR(LINE_NUMBER); - RR(TIMING_H); - RR(TIMING_V); - RR(POL_FREQ); - RR(DIVISOR); + RR(TIMING_H(0)); + RR(TIMING_V(0)); + RR(POL_FREQ(0)); + RR(DIVISOR(0)); RR(GLOBAL_ALPHA); RR(SIZE_DIG); - RR(SIZE_LCD); + RR(SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + RR(DEFAULT_COLOR(2)); + RR(TRANS_COLOR(2)); + RR(SIZE_LCD(2)); + RR(TIMING_H(2)); + RR(TIMING_V(2)); + RR(POL_FREQ(2)); + RR(DIVISOR(2)); + RR(CONFIG2); + } RR(GFX_BA0); RR(GFX_BA1); @@ -380,13 +415,22 @@ void dispc_restore_context(void) RR(GFX_WINDOW_SKIP); RR(GFX_TABLE_BA); - RR(DATA_CYCLE1); - RR(DATA_CYCLE2); - RR(DATA_CYCLE3); - - RR(CPR_COEF_R); - RR(CPR_COEF_G); - RR(CPR_COEF_B); + RR(DATA_CYCLE1(0)); + RR(DATA_CYCLE2(0)); + RR(DATA_CYCLE3(0)); + + RR(CPR_COEF_R(0)); + RR(CPR_COEF_G(0)); + RR(CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + RR(DATA_CYCLE1(2)); + RR(DATA_CYCLE2(2)); + RR(DATA_CYCLE3(2)); + + RR(CPR_COEF_B(2)); + RR(CPR_COEF_G(2)); + RR(CPR_COEF_R(2)); + } RR(GFX_PRELOAD); @@ -490,7 +534,8 @@ void dispc_restore_context(void) /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); - + if (dss_has_feature(FEAT_MGR_LCD2)) + RR(CONTROL2); /* clear spurious SYNC_LOST_DIGIT interrupts */ dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); @@ -516,42 +561,63 @@ bool dispc_go_busy(enum omap_channel channel) { int bit; - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ - return REG_GET(DISPC_CONTROL, bit, bit) == 1; + if (channel == OMAP_DSS_CHANNEL_LCD2) + return REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + return REG_GET(DISPC_CONTROL, bit, bit) == 1; } void dispc_go(enum omap_channel channel) { int bit; + bool enable_bit, go_bit; enable_clocks(1); - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 0; /* LCDENABLE */ else bit = 1; /* DIGITALENABLE */ /* if the channel is not enabled, we don't need GO */ - if (REG_GET(DISPC_CONTROL, bit, bit) == 0) + if (channel == OMAP_DSS_CHANNEL_LCD2) + enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; + + if (!enable_bit) goto end; - if (channel == OMAP_DSS_CHANNEL_LCD) + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) bit = 5; /* GOLCD */ else bit = 6; /* GODIGIT */ - if (REG_GET(DISPC_CONTROL, bit, bit) == 1) { + if (channel == OMAP_DSS_CHANNEL_LCD2) + go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; + else + go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; + + if (go_bit) { DSSERR("GO bit not down for channel %d\n", channel); goto end; } - DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT"); + DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : + (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT")); - REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); + else + REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); end: enable_clocks(0); } @@ -773,13 +839,26 @@ static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) dispc_write_reg(vsi_reg[plane-1], val); } +static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable) +{ + if (!dss_has_feature(FEAT_PRE_MULT_ALPHA)) + return; + + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) + return; + + REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28); +} + static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) { if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) return; - BUG_ON(!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1); + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + plane == OMAP_DSS_VIDEO1) + return; if (plane == OMAP_DSS_GFX) REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); @@ -851,6 +930,7 @@ static void _dispc_set_channel_out(enum omap_plane plane, { int shift; u32 val; + int chan = 0, chan2 = 0; switch (plane) { case OMAP_DSS_GFX: @@ -866,7 +946,29 @@ static void _dispc_set_channel_out(enum omap_plane plane, } val = dispc_read_reg(dispc_reg_att[plane]); - val = FLD_MOD(val, channel, shift, shift); + if (dss_has_feature(FEAT_MGR_LCD2)) { + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + chan = 0; + chan2 = 0; + break; + case OMAP_DSS_CHANNEL_DIGIT: + chan = 1; + chan2 = 0; + break; + case OMAP_DSS_CHANNEL_LCD2: + chan = 0; + chan2 = 1; + break; + default: + BUG(); + } + + val = FLD_MOD(val, chan, shift, shift); + val = FLD_MOD(val, chan2, 31, 30); + } else { + val = FLD_MOD(val, channel, shift, shift); + } dispc_write_reg(dispc_reg_att[plane], val); } @@ -923,13 +1025,13 @@ void dispc_enable_replication(enum omap_plane plane, bool enable) enable_clocks(0); } -void dispc_set_lcd_size(u16 width, u16 height) +void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) { u32 val; BUG_ON((width > (1 << 11)) || (height > (1 << 11))); val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); enable_clocks(1); - dispc_write_reg(DISPC_SIZE_LCD, val); + dispc_write_reg(DISPC_SIZE_LCD(channel), val); enable_clocks(0); } @@ -1426,12 +1528,13 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, } } -static unsigned long calc_fclk_five_taps(u16 width, u16 height, - u16 out_width, u16 out_height, enum omap_color_mode color_mode) +static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, + u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode) { u32 fclk = 0; /* FIXME venc pclk? */ - u64 tmp, pclk = dispc_pclk_rate(); + u64 tmp, pclk = dispc_pclk_rate(channel); if (height > out_height) { /* FIXME get real display PPL */ @@ -1463,8 +1566,8 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height, return fclk; } -static unsigned long calc_fclk(u16 width, u16 height, - u16 out_width, u16 out_height) +static unsigned long calc_fclk(enum omap_channel channel, u16 width, + u16 height, u16 out_width, u16 out_height) { unsigned int hf, vf; @@ -1488,7 +1591,7 @@ static unsigned long calc_fclk(u16 width, u16 height, vf = 1; /* FIXME venc pclk? */ - return dispc_pclk_rate() * vf * hf; + return dispc_pclk_rate(channel) * vf * hf; } void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out) @@ -1507,7 +1610,8 @@ static int _dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, int mirror, - u8 global_alpha) + u8 global_alpha, u8 pre_mult_alpha, + enum omap_channel channel) { const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; bool five_taps = 0; @@ -1536,29 +1640,12 @@ static int _dispc_setup_plane(enum omap_plane plane, height, pos_y, out_height); } + if (!dss_feat_color_mode_supported(plane, color_mode)) + return -EINVAL; + if (plane == OMAP_DSS_GFX) { if (width != out_width || height != out_height) return -EINVAL; - - switch (color_mode) { - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -EINVAL; - case OMAP_DSS_COLOR_RGBX32: - if (cpu_is_omap24xx()) - return -EINVAL; - /* fall through */ - case OMAP_DSS_COLOR_RGB12U: - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_RGB24P: - case OMAP_DSS_COLOR_RGB24U: - break; - - default: - return -EINVAL; - } } else { /* video plane */ @@ -1572,42 +1659,16 @@ static int _dispc_setup_plane(enum omap_plane plane, out_height > height * 8) return -EINVAL; - switch (color_mode) { - case OMAP_DSS_COLOR_RGBX32: - case OMAP_DSS_COLOR_RGB12U: - if (cpu_is_omap24xx()) - return -EINVAL; - /* fall through */ - case OMAP_DSS_COLOR_RGB16: - case OMAP_DSS_COLOR_RGB24P: - case OMAP_DSS_COLOR_RGB24U: - break; - - case OMAP_DSS_COLOR_ARGB16: - case OMAP_DSS_COLOR_ARGB32: - case OMAP_DSS_COLOR_RGBA32: - if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) - return -EINVAL; - if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && - plane == OMAP_DSS_VIDEO1) - return -EINVAL; - break; - - case OMAP_DSS_COLOR_YUV2: - case OMAP_DSS_COLOR_UYVY: + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY) cconv = 1; - break; - - default: - return -EINVAL; - } /* Must use 5-tap filter? */ five_taps = height > out_height * 2; if (!five_taps) { - fclk = calc_fclk(width, height, - out_width, out_height); + 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 && @@ -1621,7 +1682,7 @@ static int _dispc_setup_plane(enum omap_plane plane, } if (five_taps) - fclk = calc_fclk_five_taps(width, height, + fclk = calc_fclk_five_taps(channel, width, height, out_width, out_height, color_mode); DSSDBG("required fclk rate = %lu Hz\n", fclk); @@ -1693,8 +1754,8 @@ static int _dispc_setup_plane(enum omap_plane plane, _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode); - if (plane != OMAP_DSS_VIDEO1) - _dispc_setup_global_alpha(plane, global_alpha); + _dispc_set_pre_mult_alpha(plane, pre_mult_alpha); + _dispc_setup_global_alpha(plane, global_alpha); return 0; } @@ -1710,36 +1771,44 @@ static void dispc_disable_isr(void *data, u32 mask) complete(compl); } -static void _enable_lcd_out(bool enable) +static void _enable_lcd_out(enum omap_channel channel, bool enable) { - REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); + else + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); } -static void dispc_enable_lcd_out(bool enable) +static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) { struct completion frame_done_completion; bool is_on; int r; + u32 irq; enable_clocks(1); /* When we disable LCD output, we need to wait until frame is done. * Otherwise the DSS is still working, and turning off the clocks * prevents DSS from going to OFF mode */ - is_on = REG_GET(DISPC_CONTROL, 0, 0); + is_on = channel == OMAP_DSS_CHANNEL_LCD2 ? + REG_GET(DISPC_CONTROL2, 0, 0) : + REG_GET(DISPC_CONTROL, 0, 0); + + irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : + DISPC_IRQ_FRAMEDONE; if (!enable && is_on) { init_completion(&frame_done_completion); r = omap_dispc_register_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_FRAMEDONE); + &frame_done_completion, irq); if (r) DSSERR("failed to register FRAMEDONE isr\n"); } - _enable_lcd_out(enable); + _enable_lcd_out(channel, enable); if (!enable && is_on) { if (!wait_for_completion_timeout(&frame_done_completion, @@ -1747,8 +1816,7 @@ static void dispc_enable_lcd_out(bool enable) DSSERR("timeout waiting for FRAME DONE\n"); r = omap_dispc_unregister_isr(dispc_disable_isr, - &frame_done_completion, - DISPC_IRQ_FRAMEDONE); + &frame_done_completion, irq); if (r) DSSERR("failed to unregister FRAMEDONE isr\n"); @@ -1818,6 +1886,8 @@ static void dispc_enable_digit_out(bool enable) unsigned long flags; spin_lock_irqsave(&dispc.irq_lock, flags); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); @@ -1832,14 +1902,17 @@ bool dispc_is_channel_enabled(enum omap_channel channel) return !!REG_GET(DISPC_CONTROL, 0, 0); else if (channel == OMAP_DSS_CHANNEL_DIGIT) return !!REG_GET(DISPC_CONTROL, 1, 1); + else if (channel == OMAP_DSS_CHANNEL_LCD2) + return !!REG_GET(DISPC_CONTROL2, 0, 0); else BUG(); } void dispc_enable_channel(enum omap_channel channel, bool enable) { - if (channel == OMAP_DSS_CHANNEL_LCD) - dispc_enable_lcd_out(enable); + if (channel == OMAP_DSS_CHANNEL_LCD || + channel == OMAP_DSS_CHANNEL_LCD2) + dispc_enable_lcd_out(channel, enable); else if (channel == OMAP_DSS_CHANNEL_DIGIT) dispc_enable_digit_out(enable); else @@ -1848,6 +1921,9 @@ void dispc_enable_channel(enum omap_channel channel, bool enable) void dispc_lcd_enable_signal_polarity(bool act_high) { + if (!dss_has_feature(FEAT_LCDENABLEPOL)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); enable_clocks(0); @@ -1855,6 +1931,9 @@ void dispc_lcd_enable_signal_polarity(bool act_high) void dispc_lcd_enable_signal(bool enable) { + if (!dss_has_feature(FEAT_LCDENABLESIGNAL)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); enable_clocks(0); @@ -1862,20 +1941,27 @@ void dispc_lcd_enable_signal(bool enable) void dispc_pck_free_enable(bool enable) { + if (!dss_has_feature(FEAT_PCKFREEENABLE)) + return; + enable_clocks(1); REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); enable_clocks(0); } -void dispc_enable_fifohandcheck(bool enable) +void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) { enable_clocks(1); - REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); + else + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); enable_clocks(0); } -void dispc_set_lcd_display_type(enum omap_lcd_display_type type) +void dispc_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type) { int mode; @@ -1894,7 +1980,10 @@ void dispc_set_lcd_display_type(enum omap_lcd_display_type type) } enable_clocks(1); - REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); + else + REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); enable_clocks(0); } @@ -1908,25 +1997,21 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) void dispc_set_default_color(enum omap_channel channel, u32 color) { - const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, - DISPC_DEFAULT_COLOR1 }; - enable_clocks(1); - dispc_write_reg(def_reg[channel], color); + dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); enable_clocks(0); } u32 dispc_get_default_color(enum omap_channel channel) { - const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, - DISPC_DEFAULT_COLOR1 }; u32 l; BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && - channel != OMAP_DSS_CHANNEL_LCD); + channel != OMAP_DSS_CHANNEL_LCD && + channel != OMAP_DSS_CHANNEL_LCD2); enable_clocks(1); - l = dispc_read_reg(def_reg[channel]); + l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); enable_clocks(0); return l; @@ -1936,16 +2021,15 @@ void dispc_set_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type type, u32 trans_key) { - const struct dispc_reg tr_reg[] = { - DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; - enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); - dispc_write_reg(tr_reg[ch], trans_key); + dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); enable_clocks(0); } @@ -1953,21 +2037,20 @@ void dispc_get_trans_key(enum omap_channel ch, enum omap_dss_trans_key_type *type, u32 *trans_key) { - const struct dispc_reg tr_reg[] = { - DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; - enable_clocks(1); 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(tr_reg[ch]); + *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); enable_clocks(0); } @@ -1976,8 +2059,10 @@ void dispc_enable_trans_key(enum omap_channel ch, bool enable) enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); enable_clocks(0); } void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) @@ -1988,8 +2073,10 @@ void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) enable_clocks(1); if (ch == OMAP_DSS_CHANNEL_LCD) REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); - else /* OMAP_DSS_CHANNEL_DIGIT */ + else if (ch == OMAP_DSS_CHANNEL_DIGIT) REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); + else /* OMAP_DSS_CHANNEL_LCD2 */ + REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); enable_clocks(0); } bool dispc_alpha_blending_enabled(enum omap_channel ch) @@ -2003,13 +2090,14 @@ bool dispc_alpha_blending_enabled(enum omap_channel ch) 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, 18, 18); + enabled = REG_GET(DISPC_CONFIG, 19, 19); + else if (ch == OMAP_DSS_CHANNEL_LCD2) + enabled = REG_GET(DISPC_CONFIG2, 18, 18); else BUG(); enable_clocks(0); return enabled; - } @@ -2022,6 +2110,8 @@ bool dispc_trans_key_enabled(enum omap_channel ch) 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(); enable_clocks(0); @@ -2030,7 +2120,7 @@ bool dispc_trans_key_enabled(enum omap_channel ch) } -void dispc_set_tft_data_lines(u8 data_lines) +void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) { int code; @@ -2053,11 +2143,15 @@ void dispc_set_tft_data_lines(u8 data_lines) } enable_clocks(1); - REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); + if (channel == OMAP_DSS_CHANNEL_LCD2) + REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); + else + REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); enable_clocks(0); } -void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) +void dispc_set_parallel_interface_mode(enum omap_channel channel, + enum omap_parallel_interface_mode mode) { u32 l; int stallmode; @@ -2087,13 +2181,17 @@ void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) enable_clocks(1); - l = dispc_read_reg(DISPC_CONTROL); - - l = FLD_MOD(l, stallmode, 11, 11); - l = FLD_MOD(l, gpout0, 15, 15); - l = FLD_MOD(l, gpout1, 16, 16); - - dispc_write_reg(DISPC_CONTROL, l); + if (channel == OMAP_DSS_CHANNEL_LCD2) { + l = dispc_read_reg(DISPC_CONTROL2); + l = FLD_MOD(l, stallmode, 11, 11); + dispc_write_reg(DISPC_CONTROL2, l); + } else { + l = dispc_read_reg(DISPC_CONTROL); + l = FLD_MOD(l, stallmode, 11, 11); + l = FLD_MOD(l, gpout0, 15, 15); + l = FLD_MOD(l, gpout1, 16, 16); + dispc_write_reg(DISPC_CONTROL, l); + } enable_clocks(0); } @@ -2129,8 +2227,8 @@ bool dispc_lcd_timings_ok(struct omap_video_timings *timings) timings->vfp, timings->vbp); } -static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, - int vsw, int vfp, int vbp) +static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, + int hfp, int hbp, int vsw, int vfp, int vbp) { u32 timing_h, timing_v; @@ -2149,13 +2247,14 @@ static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, } enable_clocks(1); - dispc_write_reg(DISPC_TIMING_H, timing_h); - dispc_write_reg(DISPC_TIMING_V, timing_v); + dispc_write_reg(DISPC_TIMING_H(channel), timing_h); + dispc_write_reg(DISPC_TIMING_V(channel), timing_v); enable_clocks(0); } /* change name to mode? */ -void dispc_set_lcd_timings(struct omap_video_timings *timings) +void dispc_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings) { unsigned xtot, ytot; unsigned long ht, vt; @@ -2165,10 +2264,11 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) timings->vfp, timings->vbp)) BUG(); - _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp, - timings->vsw, timings->vfp, timings->vbp); + _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp, + timings->hbp, timings->vsw, timings->vfp, + timings->vbp); - dispc_set_lcd_size(timings->x_res, timings->y_res); + dispc_set_lcd_size(channel, timings->x_res, timings->y_res); xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp; ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp; @@ -2176,7 +2276,8 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) ht = (timings->pixel_clock * 1000) / xtot; vt = (timings->pixel_clock * 1000) / xtot / ytot; - DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res); + DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res, + timings->y_res); DSSDBG("pck %u\n", timings->pixel_clock); DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", timings->hsw, timings->hfp, timings->hbp, @@ -2185,21 +2286,23 @@ void dispc_set_lcd_timings(struct omap_video_timings *timings) DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); } -static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div) +static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, + u16 pck_div) { BUG_ON(lck_div < 1); BUG_ON(pck_div < 2); enable_clocks(1); - dispc_write_reg(DISPC_DIVISOR, + dispc_write_reg(DISPC_DIVISOR(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); enable_clocks(0); } -static void dispc_get_lcd_divisor(int *lck_div, int *pck_div) +static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, + int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(channel)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } @@ -2219,13 +2322,13 @@ unsigned long dispc_fclk_rate(void) return r; } -unsigned long dispc_lclk_rate(void) +unsigned long dispc_lclk_rate(enum omap_channel channel) { int lcd; unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(channel)); lcd = FLD_GET(l, 23, 16); @@ -2234,13 +2337,13 @@ unsigned long dispc_lclk_rate(void) return r / lcd; } -unsigned long dispc_pclk_rate(void) +unsigned long dispc_pclk_rate(enum omap_channel channel) { int lcd, pcd; unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR); + l = dispc_read_reg(DISPC_DIVISOR(channel)); lcd = FLD_GET(l, 23, 16); pcd = FLD_GET(l, 7, 0); @@ -2256,8 +2359,6 @@ void dispc_dump_clocks(struct seq_file *s) enable_clocks(1); - dispc_get_lcd_divisor(&lcd, &pcd); - seq_printf(s, "- DISPC -\n"); seq_printf(s, "dispc fclk source = %s\n", @@ -2265,9 +2366,25 @@ void dispc_dump_clocks(struct seq_file *s) "dss1_alwon_fclk" : "dsi1_pll_fclk"); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); - seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd); - seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd); + seq_printf(s, "- LCD1 -\n"); + + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); + + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); + seq_printf(s, "pck\t\t%-16lupck div\t%u\n", + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); + if (dss_has_feature(FEAT_MGR_LCD2)) { + seq_printf(s, "- LCD2 -\n"); + + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); + + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd); + seq_printf(s, "pck\t\t%-16lupck div\t%u\n", + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); + } enable_clocks(0); } @@ -2309,6 +2426,12 @@ void dispc_dump_irqs(struct seq_file *s) PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); PIS(WAKEUP); + if (dss_has_feature(FEAT_MGR_LCD2)) { + PIS(FRAMEDONE2); + PIS(VSYNC2); + PIS(ACBIAS_COUNT_STAT2); + PIS(SYNC_LOST2); + } #undef PIS } #endif @@ -2327,19 +2450,30 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_CONTROL); DUMPREG(DISPC_CONFIG); DUMPREG(DISPC_CAPABLE); - DUMPREG(DISPC_DEFAULT_COLOR0); - DUMPREG(DISPC_DEFAULT_COLOR1); - DUMPREG(DISPC_TRANS_COLOR0); - DUMPREG(DISPC_TRANS_COLOR1); + DUMPREG(DISPC_DEFAULT_COLOR(0)); + DUMPREG(DISPC_DEFAULT_COLOR(1)); + DUMPREG(DISPC_TRANS_COLOR(0)); + DUMPREG(DISPC_TRANS_COLOR(1)); DUMPREG(DISPC_LINE_STATUS); DUMPREG(DISPC_LINE_NUMBER); - DUMPREG(DISPC_TIMING_H); - DUMPREG(DISPC_TIMING_V); - DUMPREG(DISPC_POL_FREQ); - DUMPREG(DISPC_DIVISOR); + DUMPREG(DISPC_TIMING_H(0)); + DUMPREG(DISPC_TIMING_V(0)); + DUMPREG(DISPC_POL_FREQ(0)); + DUMPREG(DISPC_DIVISOR(0)); DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_DIG); - DUMPREG(DISPC_SIZE_LCD); + DUMPREG(DISPC_SIZE_LCD(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + DUMPREG(DISPC_CONTROL2); + DUMPREG(DISPC_CONFIG2); + DUMPREG(DISPC_DEFAULT_COLOR(2)); + DUMPREG(DISPC_TRANS_COLOR(2)); + DUMPREG(DISPC_TIMING_H(2)); + DUMPREG(DISPC_TIMING_V(2)); + DUMPREG(DISPC_POL_FREQ(2)); + DUMPREG(DISPC_DIVISOR(2)); + DUMPREG(DISPC_SIZE_LCD(2)); + } DUMPREG(DISPC_GFX_BA0); DUMPREG(DISPC_GFX_BA1); @@ -2353,13 +2487,22 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_GFX_WINDOW_SKIP); DUMPREG(DISPC_GFX_TABLE_BA); - DUMPREG(DISPC_DATA_CYCLE1); - DUMPREG(DISPC_DATA_CYCLE2); - DUMPREG(DISPC_DATA_CYCLE3); - - DUMPREG(DISPC_CPR_COEF_R); - DUMPREG(DISPC_CPR_COEF_G); - DUMPREG(DISPC_CPR_COEF_B); + DUMPREG(DISPC_DATA_CYCLE1(0)); + DUMPREG(DISPC_DATA_CYCLE2(0)); + DUMPREG(DISPC_DATA_CYCLE3(0)); + + DUMPREG(DISPC_CPR_COEF_R(0)); + DUMPREG(DISPC_CPR_COEF_G(0)); + DUMPREG(DISPC_CPR_COEF_B(0)); + if (dss_has_feature(FEAT_MGR_LCD2)) { + DUMPREG(DISPC_DATA_CYCLE1(2)); + DUMPREG(DISPC_DATA_CYCLE2(2)); + DUMPREG(DISPC_DATA_CYCLE3(2)); + + DUMPREG(DISPC_CPR_COEF_R(2)); + DUMPREG(DISPC_CPR_COEF_G(2)); + DUMPREG(DISPC_CPR_COEF_B(2)); + } DUMPREG(DISPC_GFX_PRELOAD); @@ -2458,8 +2601,8 @@ void dispc_dump_regs(struct seq_file *s) #undef DUMPREG } -static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, - bool ihs, bool ivs, u8 acbi, u8 acb) +static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, + bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb) { u32 l = 0; @@ -2476,13 +2619,14 @@ static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc, l |= FLD_VAL(acb, 7, 0); enable_clocks(1); - dispc_write_reg(DISPC_POL_FREQ, l); + dispc_write_reg(DISPC_POL_FREQ(channel), l); enable_clocks(0); } -void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb) +void dispc_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb) { - _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0, + _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, (config & OMAP_DSS_LCD_RF) != 0, (config & OMAP_DSS_LCD_IEO) != 0, (config & OMAP_DSS_LCD_IPC) != 0, @@ -2551,24 +2695,26 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, return 0; } -int dispc_set_clock_div(struct dispc_clock_info *cinfo) +int dispc_set_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo) { DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); - dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div); + dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); return 0; } -int dispc_get_clock_div(struct dispc_clock_info *cinfo) +int dispc_get_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo) { unsigned long fck; fck = dispc_fclk_rate(); - cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0); + cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16); + cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; @@ -2708,6 +2854,8 @@ static void print_irq_status(u32 status) PIS(VID2_FIFO_UNDERFLOW); PIS(SYNC_LOST); PIS(SYNC_LOST_DIGIT); + if (dss_has_feature(FEAT_MGR_LCD2)) + PIS(SYNC_LOST2); #undef PIS printk("\n"); @@ -2926,6 +3074,45 @@ static void dispc_error_worker(struct work_struct *work) } } + if (errors & DISPC_IRQ_SYNC_LOST2) { + struct omap_overlay_manager *manager = NULL; + bool enable = false; + + DSSERR("SYNC_LOST for LCD2, disabling LCD2\n"); + + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + struct omap_overlay_manager *mgr; + mgr = omap_dss_get_overlay_manager(i); + + if (mgr->id == OMAP_DSS_CHANNEL_LCD2) { + manager = mgr; + enable = mgr->device->state == + OMAP_DSS_DISPLAY_ACTIVE; + mgr->device->driver->disable(mgr->device); + break; + } + } + + if (manager) { + struct omap_dss_device *dssdev = manager->device; + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl; + ovl = omap_dss_get_overlay(i); + + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) + continue; + + if (ovl->id != 0 && ovl->manager == manager) + dispc_enable_plane(ovl->id, 0); + } + + dispc_go(manager->id); + mdelay(50); + if (enable) + dssdev->driver->enable(dssdev); + } + } + if (errors & DISPC_IRQ_OCP_ERR) { DSSERR("OCP_ERR\n"); for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { @@ -3033,6 +3220,8 @@ static void _omap_dispc_initialize_irq(void) memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, * so clear it */ @@ -3065,7 +3254,8 @@ static void _omap_dispc_initial_config(void) dispc_write_reg(DISPC_SYSCONFIG, l); /* FUNCGATED */ - REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); + if (dss_has_feature(FEAT_FUNCGATED)) + REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); /* L3 firewall setting: enable access to OCM RAM */ /* XXX this should be somewhere in plat-omap */ @@ -3139,17 +3329,18 @@ int dispc_setup_plane(enum omap_plane plane, enum omap_color_mode color_mode, bool ilace, enum omap_dss_rotation_type rotation_type, - u8 rotation, bool mirror, u8 global_alpha) + u8 rotation, bool mirror, u8 global_alpha, + u8 pre_mult_alpha, enum omap_channel channel) { int r = 0; DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n", + "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", plane, paddr, screen_width, pos_x, pos_y, width, height, out_width, out_height, ilace, color_mode, - rotation, mirror); + rotation, mirror, channel); enable_clocks(1); @@ -3161,7 +3352,8 @@ int dispc_setup_plane(enum omap_plane plane, color_mode, ilace, rotation_type, rotation, mirror, - global_alpha); + global_alpha, + pre_mult_alpha, channel); enable_clocks(0); diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 960e977a8bf0..75fb0a515430 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -40,8 +40,9 @@ static struct { } dpi; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL -static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { struct dsi_clock_info dsi_cinfo; struct dispc_clock_info dispc_cinfo; @@ -58,7 +59,7 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -69,8 +70,9 @@ static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req, return 0; } #else -static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req, - unsigned long *fck, int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; @@ -84,7 +86,7 @@ static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req, if (r) return r; - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) return r; @@ -107,17 +109,17 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, - dssdev->panel.acb); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dssdev->panel.acbi, dssdev->panel.acb); is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000, - &fck, &lck_div, &pck_div); + r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, + &lck_div, &pck_div); #else - r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000, - &fck, &lck_div, &pck_div); + r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck, + &lck_div, &pck_div); #endif if (r) goto err0; @@ -132,7 +134,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dispc_set_lcd_timings(t); + dispc_set_lcd_timings(dssdev->manager->id, t); err0: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); @@ -145,10 +147,12 @@ static int dpi_basic_init(struct omap_dss_device *dssdev) is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); - dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT : - OMAP_DSS_LCD_DISPLAY_STN); - dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + dispc_set_lcd_display_type(dssdev->manager->id, is_tft ? + OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); + dispc_set_tft_data_lines(dssdev->manager->id, + dssdev->phy.dpi.data_lines); return 0; } @@ -234,7 +238,7 @@ void dpi_set_timings(struct omap_dss_device *dssdev, dssdev->panel.timings = *timings; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { dpi_set_mode(dssdev); - dispc_go(OMAP_DSS_CHANNEL_LCD); + dispc_go(dssdev->manager->id); } } EXPORT_SYMBOL(dpi_set_timings); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index aa4f7a5fae29..ddf3a0560822 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -792,7 +792,8 @@ static int dsi_pll_power(enum dsi_pll_power_state state) } /* calculate clock rates using dividers in cinfo */ -static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo) +static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, + struct dsi_clock_info *cinfo) { if (cinfo->regn == 0 || cinfo->regn > REGN_MAX) return -EINVAL; @@ -812,7 +813,7 @@ static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo) * with DSS2_FCK source also */ cinfo->highfreq = 0; } else { - cinfo->clkin = dispc_pclk_rate(); + cinfo->clkin = dispc_pclk_rate(dssdev->manager->id); if (cinfo->clkin < 32000000) cinfo->highfreq = 0; @@ -1206,8 +1207,8 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "VP_CLK\t\t%lu\n" "VP_PCLK\t\t%lu\n", - dispc_lclk_rate(), - dispc_pclk_rate()); + dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), + dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD)); enable_clocks(0); } @@ -2888,7 +2889,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dss_setup_partial_planes(dssdev, x, y, w, h, enlarge_update_area); - dispc_set_lcd_size(*w, *h); + dispc_set_lcd_size(dssdev->manager->id, *w, *h); } return 0; @@ -2947,12 +2948,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) return r; } - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI); - dispc_enable_fifohandcheck(1); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_DSI); + dispc_enable_fifohandcheck(dssdev->manager->id, 1); - dispc_set_tft_data_lines(dssdev->ctrl.pixel_size); + dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); { struct omap_video_timings timings = { @@ -2964,7 +2967,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) .vbp = 0, }; - dispc_set_lcd_timings(&timings); + dispc_set_lcd_timings(dssdev->manager->id, &timings); } return 0; @@ -2987,7 +2990,7 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) cinfo.regm = dssdev->phy.dsi.div.regm; cinfo.regm3 = dssdev->phy.dsi.div.regm3; cinfo.regm4 = dssdev->phy.dsi.div.regm4; - r = dsi_calc_clock_rates(&cinfo); + r = dsi_calc_clock_rates(dssdev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); return r; @@ -3019,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) return r; } - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) { DSSERR("Failed to set dispc clocks\n"); return r; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 5c7940d5f282..b394951120ac 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -333,9 +333,9 @@ void dispc_disable_sidle(void); void dispc_lcd_enable_signal_polarity(bool act_high); void dispc_lcd_enable_signal(bool enable); void dispc_pck_free_enable(bool enable); -void dispc_enable_fifohandcheck(bool enable); +void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable); -void dispc_set_lcd_size(u16 width, u16 height); +void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height); void dispc_set_digit_size(u16 width, u16 height); u32 dispc_get_plane_fifo_size(enum omap_plane plane); void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high); @@ -359,7 +359,8 @@ int dispc_setup_plane(enum omap_plane plane, bool ilace, enum omap_dss_rotation_type rotation_type, u8 rotation, bool mirror, - u8 global_alpha); + u8 global_alpha, u8 pre_mult_alpha, + enum omap_channel channel); bool dispc_go_busy(enum omap_channel channel); void dispc_go(enum omap_channel channel); @@ -368,9 +369,11 @@ bool dispc_is_channel_enabled(enum omap_channel channel); int dispc_enable_plane(enum omap_plane plane, bool enable); void dispc_enable_replication(enum omap_plane plane, bool enable); -void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode); -void dispc_set_tft_data_lines(u8 data_lines); -void dispc_set_lcd_display_type(enum omap_lcd_display_type type); +void dispc_set_parallel_interface_mode(enum omap_channel channel, + enum omap_parallel_interface_mode mode); +void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines); +void dispc_set_lcd_display_type(enum omap_channel channel, + enum omap_lcd_display_type type); void dispc_set_loadmode(enum omap_dss_load_mode mode); void dispc_set_default_color(enum omap_channel channel, u32 color); @@ -387,17 +390,21 @@ bool dispc_trans_key_enabled(enum omap_channel ch); bool dispc_alpha_blending_enabled(enum omap_channel ch); bool dispc_lcd_timings_ok(struct omap_video_timings *timings); -void dispc_set_lcd_timings(struct omap_video_timings *timings); +void dispc_set_lcd_timings(enum omap_channel channel, + struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); -unsigned long dispc_lclk_rate(void); -unsigned long dispc_pclk_rate(void); -void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb); +unsigned long dispc_lclk_rate(enum omap_channel channel); +unsigned long dispc_pclk_rate(enum omap_channel channel); +void dispc_set_pol_freq(enum omap_channel channel, + enum omap_panel_config config, u8 acbi, u8 acb); void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, struct dispc_clock_info *cinfo); int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo); -int dispc_set_clock_div(struct dispc_clock_info *cinfo); -int dispc_get_clock_div(struct dispc_clock_info *cinfo); +int dispc_set_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo); +int dispc_get_clock_div(enum omap_channel channel, + struct dispc_clock_info *cinfo); /* VENC */ @@ -424,8 +431,8 @@ void rfbi_dump_regs(struct seq_file *s); int rfbi_configure(int rfbi_module, int bpp, int lines); void rfbi_enable_rfbi(bool enable); -void rfbi_transfer_area(u16 width, u16 height, - void (callback)(void *data), void *data); +void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, + u16 height, void (callback)(void *data), void *data); void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 867f68de125f..cf3ef696e141 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -82,6 +82,18 @@ static const enum omap_display_type omap3_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_VENC, }; +static const enum omap_display_type omap4_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_VENC, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, +}; + static const enum omap_color_mode omap2_dss_supported_color_modes[] = { /* OMAP_DSS_GFX */ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | @@ -127,6 +139,10 @@ static struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), + .has_feature = + FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | + FEAT_PCKFREEENABLE | FEAT_FUNCGATED, + .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, @@ -134,11 +150,29 @@ static struct omap_dss_features omap2_dss_features = { }; /* OMAP3 DSS Features */ -static struct omap_dss_features omap3_dss_features = { +static struct omap_dss_features omap3430_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | + FEAT_FUNCGATED, + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + +static struct omap_dss_features omap3630_dss_features = { .reg_fields = omap3_dss_reg_fields, .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), - .has_feature = FEAT_GLOBAL_ALPHA, + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | + FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | + FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED, .num_mgrs = 2, .num_ovls = 3, @@ -146,6 +180,21 @@ static struct omap_dss_features omap3_dss_features = { .supported_color_modes = omap3_dss_supported_color_modes, }; +/* OMAP4 DSS Features */ +static struct omap_dss_features omap4_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .has_feature = + FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | + FEAT_MGR_LCD2, + + .num_mgrs = 3, + .num_ovls = 3, + .supported_displays = omap4_dss_supported_displays, + .supported_color_modes = omap3_dss_supported_color_modes, +}; + /* Functions returning values related to a DSS feature */ int dss_feat_get_num_mgrs(void) { @@ -167,6 +216,13 @@ enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) return omap_current_dss_features->supported_color_modes[plane]; } +bool dss_feat_color_mode_supported(enum omap_plane plane, + enum omap_color_mode color_mode) +{ + return omap_current_dss_features->supported_color_modes[plane] & + color_mode; +} + /* DSS has_feature check */ bool dss_has_feature(enum dss_feat_id id) { @@ -186,6 +242,10 @@ void dss_features_init(void) { if (cpu_is_omap24xx()) omap_current_dss_features = &omap2_dss_features; + else if (cpu_is_omap3630()) + omap_current_dss_features = &omap3630_dss_features; + else if (cpu_is_omap34xx()) + omap_current_dss_features = &omap3430_dss_features; else - omap_current_dss_features = &omap3_dss_features; + omap_current_dss_features = &omap4_dss_features; } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index cb231eaa9b31..b9c70be92588 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -20,13 +20,19 @@ #ifndef __OMAP2_DSS_FEATURES_H #define __OMAP2_DSS_FEATURES_H -#define MAX_DSS_MANAGERS 2 +#define MAX_DSS_MANAGERS 3 #define MAX_DSS_OVERLAYS 3 /* DSS has feature id */ enum dss_feat_id { FEAT_GLOBAL_ALPHA = 1 << 0, FEAT_GLOBAL_ALPHA_VID1 = 1 << 1, + FEAT_PRE_MULT_ALPHA = 1 << 2, + FEAT_LCDENABLEPOL = 1 << 3, + FEAT_LCDENABLESIGNAL = 1 << 4, + FEAT_PCKFREEENABLE = 1 << 5, + FEAT_FUNCGATED = 1 << 6, + FEAT_MGR_LCD2 = 1 << 7, }; /* DSS register field id */ @@ -43,6 +49,8 @@ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); +bool dss_feat_color_mode_supported(enum omap_plane plane, + enum omap_color_mode color_mode); bool dss_has_feature(enum dss_feat_id id); void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 545e9b9a4d92..172d4e697309 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -406,6 +406,7 @@ struct overlay_cache_data { u16 out_width; /* if 0, out_width == width */ u16 out_height; /* if 0, out_height == height */ u8 global_alpha; + u8 pre_mult_alpha; enum omap_channel channel; bool replication; @@ -512,11 +513,14 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) unsigned long timeout = msecs_to_jiffies(500); u32 irq; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD; - else - irq = DISPC_IRQ_VSYNC; - + } else { + if (mgr->id == OMAP_DSS_CHANNEL_LCD) + irq = DISPC_IRQ_VSYNC; + else + irq = DISPC_IRQ_VSYNC2; + } return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); } @@ -524,7 +528,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); struct manager_cache_data *mc; - enum omap_channel channel; u32 irq; int r; int i; @@ -535,7 +538,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; @@ -543,11 +545,14 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (mode != OMAP_DSS_UPDATE_AUTO) return 0; - irq = DISPC_IRQ_FRAMEDONE; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; } else { - irq = DISPC_IRQ_VSYNC; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; } - channel = OMAP_DSS_CHANNEL_LCD; } mc = &dss_cache.manager_cache[mgr->id]; @@ -594,7 +599,6 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); - enum omap_channel channel; struct overlay_cache_data *oc; struct omap_dss_device *dssdev; u32 irq; @@ -611,7 +615,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; - channel = OMAP_DSS_CHANNEL_DIGIT; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { enum omap_dss_update_mode mode; @@ -619,11 +622,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (mode != OMAP_DSS_UPDATE_AUTO) return 0; - irq = DISPC_IRQ_FRAMEDONE; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_FRAMEDONE + : DISPC_IRQ_FRAMEDONE2; } else { - irq = DISPC_IRQ_VSYNC; + irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? + DISPC_IRQ_VSYNC + : DISPC_IRQ_VSYNC2; } - channel = OMAP_DSS_CHANNEL_LCD; } oc = &dss_cache.overlay_cache[ovl->id]; @@ -842,7 +848,9 @@ static int configure_overlay(enum omap_plane plane) c->rotation_type, c->rotation, c->mirror, - c->global_alpha); + c->global_alpha, + c->pre_mult_alpha, + c->channel); if (r) { /* this shouldn't happen */ @@ -894,10 +902,10 @@ static int configure_dispc(void) r = 0; busy = false; - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); - mgr_go[0] = false; - mgr_go[1] = false; + for (i = 0; i < num_mgrs; i++) { + mgr_busy[i] = dispc_go_busy(i); + mgr_go[i] = false; + } /* Commit overlay settings */ for (i = 0; i < num_ovls; ++i) { @@ -1156,9 +1164,10 @@ static void dss_apply_irq_handler(void *data, u32 mask) const int num_mgrs = dss_feat_get_num_mgrs(); int i, r; bool mgr_busy[MAX_DSS_MANAGERS]; + u32 irq_mask; - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); + for (i = 0; i < num_mgrs; i++) + mgr_busy[i] = dispc_go_busy(i); spin_lock(&dss_cache.lock); @@ -1179,8 +1188,8 @@ static void dss_apply_irq_handler(void *data, u32 mask) goto end; /* re-read busy flags */ - mgr_busy[0] = dispc_go_busy(0); - mgr_busy[1] = dispc_go_busy(1); + for (i = 0; i < num_mgrs; i++) + mgr_busy[i] = dispc_go_busy(i); /* keep running as long as there are busy managers, so that * we can collect overlay-applied information */ @@ -1189,9 +1198,12 @@ static void dss_apply_irq_handler(void *data, u32 mask) goto end; } - omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, - DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN); + 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: @@ -1265,6 +1277,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) oc->out_width = ovl->info.out_width; oc->out_height = ovl->info.out_height; oc->global_alpha = ovl->info.global_alpha; + oc->pre_mult_alpha = ovl->info.pre_mult_alpha; oc->replication = dss_use_replication(dssdev, ovl->info.color_mode); @@ -1383,9 +1396,14 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) r = 0; dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); if (!dss_cache.irq_enabled) { - r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, - DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | - DISPC_IRQ_EVSYNC_EVEN); + 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(); @@ -1477,6 +1495,10 @@ int dss_init_overlay_managers(struct platform_device *pdev) 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; diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 75642c22cac7..456efef03c20 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -257,6 +257,43 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, return size; } +static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + ovl->info.pre_mult_alpha); +} + +static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + /* only GFX and Video2 plane support pre alpha multiplied + * set zero for Video1 plane + */ + if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && + ovl->id == OMAP_DSS_VIDEO1) + info.pre_mult_alpha = 0; + else + info.pre_mult_alpha = simple_strtoul(buf, NULL, 10); + + 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; +} + struct overlay_attribute { struct attribute attr; ssize_t (*show)(struct omap_overlay *, char *); @@ -280,6 +317,9 @@ static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, overlay_enabled_show, overlay_enabled_store); static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, overlay_global_alpha_show, overlay_global_alpha_store); +static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, + overlay_pre_mult_alpha_show, + overlay_pre_mult_alpha_store); static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_name.attr, @@ -290,6 +330,7 @@ static struct attribute *overlay_sysfs_attrs[] = { &overlay_attr_output_size.attr, &overlay_attr_enabled.attr, &overlay_attr_global_alpha.attr, + &overlay_attr_pre_mult_alpha.attr, NULL }; @@ -623,12 +664,22 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) int i; struct omap_overlay_manager *lcd_mgr; struct omap_overlay_manager *tv_mgr; + struct omap_overlay_manager *lcd2_mgr = NULL; struct omap_overlay_manager *mgr = NULL; lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD); tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); - - if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { + if (dss_has_feature(FEAT_MGR_LCD2)) + lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2); + + if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { + if (!lcd2_mgr->device || force) { + if (lcd2_mgr->device) + lcd2_mgr->unset_device(lcd2_mgr); + lcd2_mgr->set_device(lcd2_mgr, dssdev); + mgr = lcd2_mgr; + } + } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { if (!lcd_mgr->device || force) { if (lcd_mgr->device) lcd_mgr->unset_device(lcd_mgr); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index bbe62464e92d..10a2ffe02882 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -301,8 +301,8 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -void rfbi_transfer_area(u16 width, u16 height, - void (callback)(void *data), void *data) +void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, + u16 height, void (*callback)(void *data), void *data) { u32 l; @@ -311,9 +311,9 @@ void rfbi_transfer_area(u16 width, u16 height, DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dispc_set_lcd_size(width, height); + dispc_set_lcd_size(dssdev->manager->id, width, height); - dispc_enable_channel(OMAP_DSS_CHANNEL_LCD, true); + dispc_enable_channel(dssdev->manager->id, true); rfbi.framedone_callback = callback; rfbi.framedone_callback_data = data; @@ -887,7 +887,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dss_setup_partial_planes(dssdev, x, y, w, h, true); - dispc_set_lcd_size(*w, *h); + dispc_set_lcd_size(dssdev->manager->id, *w, *h); } return 0; @@ -899,7 +899,7 @@ int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), void *data) { if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - rfbi_transfer_area(w, h, callback, data); + rfbi_transfer_area(dssdev, w, h, callback, data); } else { struct omap_overlay *ovl; void __iomem *addr; @@ -1018,11 +1018,13 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) goto err1; } - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_RFBI); - dispc_set_tft_data_lines(dssdev->ctrl.pixel_size); + dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); rfbi_configure(dssdev->phy.rfbi.channel, dssdev->ctrl.pixel_size, diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index ee07a3cc22ef..b64adf7dfc88 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -35,12 +35,16 @@ static struct { struct regulator *vdds_sdi_reg; } sdi; -static void sdi_basic_init(void) +static void sdi_basic_init(struct omap_dss_device *dssdev) + { - dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); + dispc_set_parallel_interface_mode(dssdev->manager->id, + OMAP_DSS_PARALLELMODE_BYPASS); + + dispc_set_lcd_display_type(dssdev->manager->id, + OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); - dispc_set_tft_data_lines(24); + dispc_set_tft_data_lines(dssdev->manager->id, 24); dispc_lcd_enable_signal_polarity(1); } @@ -68,20 +72,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) if (!sdi.skip_init) dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - sdi_basic_init(); + sdi_basic_init(dssdev); /* 15.5.9.1.2 */ dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; - dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi, - dssdev->panel.acb); + dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, + dssdev->panel.acbi, dssdev->panel.acb); if (!sdi.skip_init) { r = dss_calc_clock_div(1, t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); } else { r = dss_get_clock_div(&dss_cinfo); - r = dispc_get_clock_div(&dispc_cinfo); + r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo); } if (r) @@ -102,13 +106,13 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dispc_set_lcd_timings(t); + dispc_set_lcd_timings(dssdev->manager->id, t); r = dss_set_clock_div(&dss_cinfo); if (r) goto err2; - r = dispc_set_clock_div(&dispc_cinfo); + r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) goto err2; diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 6a704f176c22..4fdab8e9c496 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2132,8 +2132,9 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) char *str, *options, *this_opt; int r = 0; - str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL); - strcpy(str, def_mode); + str = kstrdup(def_mode, GFP_KERNEL); + if (!str) + return -ENOMEM; options = str; while (!r && (this_opt = strsep(&options, ",")) != NULL) { diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 618f36bec10d..da388186d617 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -331,7 +331,7 @@ static int riva_bl_get_brightness(struct backlight_device *bd) return bd->props.brightness; } -static struct backlight_ops riva_bl_ops = { +static const struct backlight_ops riva_bl_ops = { .get_brightness = riva_bl_get_brightness, .update_status = riva_bl_update_status, }; diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 46b430978bcc..61c819e35f7f 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/mm.h> @@ -918,9 +919,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, } info->clk = clk_get(NULL, "lcd"); - if (!info->clk || IS_ERR(info->clk)) { + if (IS_ERR(info->clk)) { printk(KERN_ERR "failed to get lcd clock source\n"); - ret = -ENOENT; + ret = PTR_ERR(info->clk); goto release_irq; } diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 8c59cc8c5a9c..74d9f546a2e8 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/workqueue.h> +#include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/initval.h> @@ -221,6 +222,7 @@ struct sh_hdmi { struct delayed_work edid_work; struct fb_var_screeninfo var; struct fb_monspecs monspec; + struct notifier_block notifier; }; static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) @@ -737,7 +739,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, struct fb_modelist *modelist = NULL; unsigned int f_width = 0, f_height = 0, f_refresh = 0; unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ - bool exact_match = false; + bool scanning = false, preferred_bad = false; u8 edid[128]; char *forced; int i; @@ -800,6 +802,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, if (i < 2) { f_width = 0; f_height = 0; + } else { + /* The user wants us to use the EDID data */ + scanning = true; } dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", f_width, f_height, f_refresh); @@ -807,37 +812,56 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, /* Walk monitor modes to find the best or the exact match */ for (i = 0, mode = hdmi->monspec.modedb; - f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; + i < hdmi->monspec.modedb_len && scanning; i++, mode++) { unsigned long rate_error; - /* No interest in unmatching modes */ - if (f_width != mode->xres || f_height != mode->yres) + if (!f_width && !f_height) { + /* + * A parameter string "video=sh_mobile_lcdc:0x0" means + * use the preferred EDID mode. If it is rejected by + * .fb_check_var(), keep looking, until an acceptable + * one is found. + */ + if ((mode->flag & FB_MODE_IS_FIRST) || preferred_bad) + scanning = false; + else + continue; + } else if (f_width != mode->xres || f_height != mode->yres) { + /* No interest in unmatching modes */ continue; + } rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); - if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) - /* - * Exact match if either the refresh rate matches or it - * hasn't been specified and we've found a mode, for - * which we can configure the clock precisely - */ - exact_match = true; - else if (found && found_rate_error <= rate_error) - /* - * We otherwise search for the closest matching clock - * rate - either if no refresh rate has been specified - * or we cannot find an exactly matching one - */ - continue; + if (scanning) { + if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) + /* + * Exact match if either the refresh rate + * matches or it hasn't been specified and we've + * found a mode, for which we can configure the + * clock precisely + */ + scanning = false; + else if (found && found_rate_error <= rate_error) + /* + * We otherwise search for the closest matching + * clock rate - either if no refresh rate has + * been specified or we cannot find an exactly + * matching one + */ + continue; + } /* Check if supported: sufficient fb memory, supported clock-rate */ fb_videomode_to_var(var, mode); + var->bits_per_pixel = info->var.bits_per_pixel; + if (info && info->fbops->fb_check_var && info->fbops->fb_check_var(var, info)) { - exact_match = false; + scanning = true; + preferred_bad = true; continue; } @@ -855,9 +879,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, * driver, and passing ->info with HDMI platform data. */ if (info && !found) { - modelist = hdmi->info->modelist.next && - !list_empty(&hdmi->info->modelist) ? - list_entry(hdmi->info->modelist.next, + modelist = info->modelist.next && + !list_empty(&info->modelist) ? + list_entry(info->modelist.next, struct fb_modelist, list) : NULL; @@ -1100,6 +1124,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { + struct fb_info *info = hdmi->info; unsigned long parent_rate = 0, hdmi_rate; /* A device has been plugged in */ @@ -1121,22 +1146,21 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) /* Switched to another (d) power-save mode */ msleep(10); - if (!hdmi->info) + if (!info) goto out; - ch = hdmi->info->par; + ch = info->par; acquire_console_sem(); /* HDMI plug in */ if (!sh_hdmi_must_reconfigure(hdmi) && - hdmi->info->state == FBINFO_STATE_RUNNING) { + info->state == FBINFO_STATE_RUNNING) { /* * First activation with the default monitor - just turn * on, if we run a resume here, the logo disappears */ - if (lock_fb_info(hdmi->info)) { - struct fb_info *info = hdmi->info; + if (lock_fb_info(info)) { info->var.width = hdmi->var.width; info->var.height = hdmi->var.height; sh_hdmi_display_on(hdmi, info); @@ -1144,7 +1168,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) } } else { /* New monitor or have to wake up */ - fb_set_suspend(hdmi->info, 0); + fb_set_suspend(info, 0); } release_console_sem(); @@ -1175,13 +1199,6 @@ out: } static int sh_hdmi_notify(struct notifier_block *nb, - unsigned long action, void *data); - -static struct notifier_block sh_hdmi_notifier = { - .notifier_call = sh_hdmi_notify, -}; - -static int sh_hdmi_notify(struct notifier_block *nb, unsigned long action, void *data) { struct fb_event *event = data; @@ -1190,7 +1207,7 @@ static int sh_hdmi_notify(struct notifier_block *nb, struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; struct sh_hdmi *hdmi = board_cfg->board_data; - if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) + if (!hdmi || nb != &hdmi->notifier || hdmi->info != info) return NOTIFY_DONE; switch(action) { @@ -1209,11 +1226,11 @@ static int sh_hdmi_notify(struct notifier_block *nb, * temporarily, synchronise with the work queue and re-acquire * the info->lock. */ - unlock_fb_info(hdmi->info); + unlock_fb_info(info); mutex_lock(&hdmi->mutex); hdmi->info = NULL; mutex_unlock(&hdmi->mutex); - lock_fb_info(hdmi->info); + lock_fb_info(info); return NOTIFY_OK; } return NOTIFY_DONE; @@ -1311,6 +1328,9 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto ecodec; } + hdmi->notifier.notifier_call = sh_hdmi_notify; + fb_register_client(&hdmi->notifier); + return 0; ecodec: @@ -1341,6 +1361,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) snd_soc_unregister_codec(&pdev->dev); + fb_unregister_client(&hdmi->notifier); + board_cfg->display_on = NULL; board_cfg->display_off = NULL; board_cfg->board_data = NULL; diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index dee64c3b1e67..2ab704118c44 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -536,7 +536,7 @@ static int sstfb_set_par(struct fb_info *info) fbiinit2 = sst_read(FBIINIT2); fbiinit3 = sst_read(FBIINIT3); - /* everything is reset. we enable fbiinit2/3 remap : dac acces ok */ + /* everything is reset. we enable fbiinit2/3 remap : dac access ok */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 7617f12e4fd7..0e120d67eb65 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -215,6 +215,33 @@ static int vt8500lcd_pan_display(struct fb_var_screeninfo *var, return 0; } +/* + * vt8500lcd_blank(): + * Blank the display by setting all palette values to zero. Note, + * True Color modes do not really use the palette, so this will not + * blank the display in all modes. + */ +static int vt8500lcd_blank(int blank, struct fb_info *info) +{ + int i; + + switch (blank) { + case FB_BLANK_POWERDOWN: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR || + info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + for (i = 0; i < 256; i++) + vt8500lcd_setcolreg(i, 0, 0, 0, 0, info); + case FB_BLANK_UNBLANK: + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR || + info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + fb_set_cmap(&info->cmap, info); + } + return 0; +} + static struct fb_ops vt8500lcd_ops = { .owner = THIS_MODULE, .fb_set_par = vt8500lcd_set_par, @@ -225,6 +252,7 @@ static struct fb_ops vt8500lcd_ops = { .fb_sync = wmt_ge_sync, .fb_ioctl = vt8500lcd_ioctl, .fb_pan_display = vt8500lcd_pan_display, + .fb_blank = vt8500lcd_blank, }; static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id) diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index 1f51366417b9..f0c909625bd1 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -16,6 +16,17 @@ config W1_SLAVE_SMEM Say Y here if you want to connect 1-wire simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire. +config W1_SLAVE_DS2423 + tristate "Counter 1-wire device (DS2423)" + select CRC16 + help + If you enable this you can read the counter values available + in the DS2423 chipset from the w1_slave file under the + sys file system. + + Say Y here if you want to use a 1-wire + counter family device (DS2423). + config W1_SLAVE_DS2431 tristate "1kb EEPROM family support (DS2431)" help diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile index f1f51f19b129..3c76350a24f7 100644 --- a/drivers/w1/slaves/Makefile +++ b/drivers/w1/slaves/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o +obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o diff --git a/drivers/w1/slaves/w1_ds2423.c b/drivers/w1/slaves/w1_ds2423.c new file mode 100644 index 000000000000..7a7dbe5026f1 --- /dev/null +++ b/drivers/w1/slaves/w1_ds2423.c @@ -0,0 +1,166 @@ +/* + * w1_ds2423.c + * + * Copyright (c) 2010 Mika Laitio <lamikr@pilppa.org> + * + * This driver will read and write the value of 4 counters to w1_slave file in + * sys filesystem. + * Inspired by the w1_therm and w1_ds2431 drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the therms 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/moduleparam.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/crc16.h> + +#include "../w1.h" +#include "../w1_int.h" +#include "../w1_family.h" + +#define CRC16_VALID 0xb001 +#define CRC16_INIT 0 + +#define COUNTER_COUNT 4 +#define READ_BYTE_COUNT 42 + +static ssize_t w1_counter_read(struct device *device, + struct device_attribute *attr, char *buf); + +static struct device_attribute w1_counter_attr = + __ATTR(w1_slave, S_IRUGO, w1_counter_read, NULL); + +static ssize_t w1_counter_read(struct device *device, + struct device_attribute *attr, char *out_buf) +{ + struct w1_slave *sl = dev_to_w1_slave(device); + struct w1_master *dev = sl->master; + u8 rbuf[COUNTER_COUNT * READ_BYTE_COUNT]; + u8 wrbuf[3]; + int rom_addr; + int read_byte_count; + int result; + ssize_t c; + int ii; + int p; + int crc; + + c = PAGE_SIZE; + rom_addr = (12 << 5) + 31; + wrbuf[0] = 0xA5; + wrbuf[1] = rom_addr & 0xFF; + wrbuf[2] = rom_addr >> 8; + mutex_lock(&dev->mutex); + if (!w1_reset_select_slave(sl)) { + w1_write_block(dev, wrbuf, 3); + read_byte_count = 0; + for (p = 0; p < 4; p++) { + /* + * 1 byte for first bytes in ram page read + * 4 bytes for counter + * 4 bytes for zero bits + * 2 bytes for crc + * 31 remaining bytes from the ram page + */ + read_byte_count += w1_read_block(dev, + rbuf + (p * READ_BYTE_COUNT), READ_BYTE_COUNT); + for (ii = 0; ii < READ_BYTE_COUNT; ++ii) + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "%02x ", + rbuf[(p * READ_BYTE_COUNT) + ii]); + if (read_byte_count != (p + 1) * READ_BYTE_COUNT) { + dev_warn(device, + "w1_counter_read() returned %u bytes " + "instead of %d bytes wanted.\n", + read_byte_count, + READ_BYTE_COUNT); + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "crc=NO\n"); + } else { + if (p == 0) { + crc = crc16(CRC16_INIT, wrbuf, 3); + crc = crc16(crc, rbuf, 11); + } else { + /* + * DS2423 calculates crc from all bytes + * read after the previous crc bytes. + */ + crc = crc16(CRC16_INIT, + (rbuf + 11) + + ((p - 1) * READ_BYTE_COUNT), + READ_BYTE_COUNT); + } + if (crc == CRC16_VALID) { + result = 0; + for (ii = 4; ii > 0; ii--) { + result <<= 8; + result |= rbuf[(p * + READ_BYTE_COUNT) + ii]; + } + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "crc=YES c=%d\n", result); + } else { + c -= snprintf(out_buf + PAGE_SIZE - c, + c, "crc=NO\n"); + } + } + } + } else { + c -= snprintf(out_buf + PAGE_SIZE - c, c, "Connection error"); + } + mutex_unlock(&dev->mutex); + return PAGE_SIZE - c; +} + +static int w1_f1d_add_slave(struct w1_slave *sl) +{ + return device_create_file(&sl->dev, &w1_counter_attr); +} + +static void w1_f1d_remove_slave(struct w1_slave *sl) +{ + device_remove_file(&sl->dev, &w1_counter_attr); +} + +static struct w1_family_ops w1_f1d_fops = { + .add_slave = w1_f1d_add_slave, + .remove_slave = w1_f1d_remove_slave, +}; + +static struct w1_family w1_family_1d = { + .fid = W1_COUNTER_DS2423, + .fops = &w1_f1d_fops, +}; + +static int __init w1_f1d_init(void) +{ + return w1_register_family(&w1_family_1d); +} + +static void __exit w1_f1d_exit(void) +{ + w1_unregister_family(&w1_family_1d); +} + +module_init(w1_f1d_init); +module_exit(w1_f1d_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mika Laitio <lamikr@pilppa.org>"); +MODULE_DESCRIPTION("w1 family 1d driver for DS2423, 4 counters and 4kb ram"); diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 3ca1b9298f21..f3b636d7cafe 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h @@ -30,6 +30,7 @@ #define W1_FAMILY_SMEM_01 0x01 #define W1_FAMILY_SMEM_81 0x81 #define W1_THERM_DS18S20 0x10 +#define W1_COUNTER_DS2423 0x1D #define W1_THERM_DS1822 0x22 #define W1_EEPROM_DS2433 0x23 #define W1_THERM_DS18B20 0x28 diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index a5ad77ef4266..2e2400e7322e 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -409,15 +409,26 @@ config ALIM7101_WDT Most people will say N. config F71808E_WDT - tristate "Fintek F71808E, F71882FG and F71889FG Watchdog" + tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" depends on X86 && EXPERIMENTAL help This is the driver for the hardware watchdog on the Fintek - F71808E, F71882FG and F71889FG Super I/O controllers. + F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. You can compile this driver directly into the kernel, or use it as a module. The module will be called f71808e_wdt. +config SP5100_TCO + tristate "AMD/ATI SP5100 TCO Timer/Watchdog" + depends on X86 && PCI + ---help--- + Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO + (Total Cost of Ownership) timer is a watchdog timer that will reboot + the machine after its expiration. The expiration time can be + configured with the "heartbeat" parameter. + + To compile this driver as a module, choose M here: the + module will be called sp5100_tco. config GEODE_WDT tristate "AMD Geode CS5535/CS5536 Watchdog" @@ -631,6 +642,24 @@ config PC87413_WDT Most people will say N. +config NV_TCO + tristate "nVidia TCO Timer/Watchdog" + depends on X86 && PCI + ---help--- + Hardware driver for the TCO timer built into the nVidia Hub family + (such as the MCP51). The TCO (Total Cost of Ownership) timer is a + watchdog timer that will reboot the machine after its second + expiration. The expiration time can be configured with the + "heartbeat" parameter. + + On some motherboards the driver may fail to reset the chipset's + NO_REBOOT flag which prevents the watchdog from rebooting the + machine. If this is the case you will get a kernel message like + "failed to reset NO_REBOOT flag, reboot disabled by hardware". + + To compile this driver as a module, choose M here: the + module will be called nv_tco. + config RDC321X_WDT tristate "RDC R-321x SoC watchdog" depends on X86_RDC321X @@ -722,14 +751,15 @@ config SMSC37B787_WDT Most people will say N. config W83627HF_WDT - tristate "W83627HF Watchdog Timer" + tristate "W83627HF/W83627DHG Watchdog Timer" depends on X86 ---help--- This is the driver for the hardware watchdog on the W83627HF chipset as used in Advantech PC-9578 and Tyan S2721-533 motherboards - (and likely others). This watchdog simply watches your kernel to - make sure it doesn't freeze, and if it does, it reboots your computer - after a certain amount of time. + (and likely others). The driver also supports the W83627DHG chip. + This watchdog simply watches your kernel to make sure it doesn't + freeze, and if it does, it reboots your computer after a certain + amount of time. To compile this driver as a module, choose M here: the module will be called w83627hf_wdt. @@ -832,10 +862,22 @@ config SBC_EPX_C3_WATCHDOG # M68K Architecture -# M68KNOMMU Architecture +config M548x_WATCHDOG + tristate "MCF548x watchdog support" + depends on M548x + help + To compile this driver as a module, choose M here: the + module will be called m548x_wdt. # MIPS Architecture +config ATH79_WDT + tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog" + depends on ATH79 + help + Hardware driver for the built-in watchdog timer on the Atheros + AR71XX/AR724X/AR913X SoCs. + config BCM47XX_WDT tristate "Broadcom BCM47xx Watchdog Timer" depends on BCM47XX diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 4b0ef386229d..dd776651917c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o +obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o obj-$(CONFIG_GEODE_WDT) += geodewdt.o obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_SBC_FITPC2_WATCHDOG) += sbc_fitpc2_wdt.o @@ -86,6 +87,7 @@ obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o +obj-$(CONFIG_NV_TCO) += nv_tco.o obj-$(CONFIG_RDC321X_WDT) += rdc321x_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_SBC8360_WDT) += sbc8360.o @@ -104,10 +106,10 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o # M32R Architecture # M68K Architecture - -# M68KNOMMU Architecture +obj-$(CONFIG_M548x_WATCHDOG) += m548x_wdt.o # MIPS Architecture +obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index 1e9caea8ff8a..fa4d36033552 100644 --- a/drivers/watchdog/alim1535_wdt.c +++ b/drivers/watchdog/alim1535_wdt.c @@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this, * want to register another driver on the same PCI id. */ -static struct pci_device_id ali_pci_tbl[] = { +static struct pci_device_id ali_pci_tbl[] __used = { { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, { 0, }, diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index d8d4da9a483d..4b7a2b4138ed 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c @@ -430,7 +430,7 @@ err_out: module_init(alim7101_wdt_init); module_exit(alim7101_wdt_unload); -static struct pci_device_id alim7101_pci_tbl[] __devinitdata = { +static struct pci_device_id alim7101_pci_tbl[] __devinitdata __used = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, { } diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c new file mode 100644 index 000000000000..725c84bfdd76 --- /dev/null +++ b/drivers/watchdog/ath79_wdt.c @@ -0,0 +1,305 @@ +/* + * Atheros AR71XX/AR724X/AR913X built-in hardware watchdog timer. + * + * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> + * + * This driver was based on: drivers/watchdog/ixp4xx_wdt.c + * Author: Deepak Saxena <dsaxena@plexity.net> + * Copyright 2004 (c) MontaVista, Software, Inc. + * + * which again was based on sa1100 driver, + * Copyright (C) 2000 Oleg Drokin <green@crimea.edu> + * + * 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/bitops.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/watchdog.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <asm/mach-ath79/ath79.h> +#include <asm/mach-ath79/ar71xx_regs.h> + +#define DRIVER_NAME "ath79-wdt" + +#define WDT_TIMEOUT 15 /* seconds */ + +#define WDOG_CTRL_LAST_RESET BIT(31) +#define WDOG_CTRL_ACTION_MASK 3 +#define WDOG_CTRL_ACTION_NONE 0 /* no action */ +#define WDOG_CTRL_ACTION_GPI 1 /* general purpose interrupt */ +#define WDOG_CTRL_ACTION_NMI 2 /* NMI */ +#define WDOG_CTRL_ACTION_FCR 3 /* full chip reset */ + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " + "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static int timeout = WDT_TIMEOUT; +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds " + "(default=" __MODULE_STRING(WDT_TIMEOUT) "s)"); + +static unsigned long wdt_flags; + +#define WDT_FLAGS_BUSY 0 +#define WDT_FLAGS_EXPECT_CLOSE 1 + +static struct clk *wdt_clk; +static unsigned long wdt_freq; +static int boot_status; +static int max_timeout; + +static inline void ath79_wdt_keepalive(void) +{ + ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout); +} + +static inline void ath79_wdt_enable(void) +{ + ath79_wdt_keepalive(); + ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR); +} + +static inline void ath79_wdt_disable(void) +{ + ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE); +} + +static int ath79_wdt_set_timeout(int val) +{ + if (val < 1 || val > max_timeout) + return -EINVAL; + + timeout = val; + ath79_wdt_keepalive(); + + return 0; +} + +static int ath79_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags)) + return -EBUSY; + + clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + ath79_wdt_enable(); + + return nonseekable_open(inode, file); +} + +static int ath79_wdt_release(struct inode *inode, struct file *file) +{ + if (test_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags)) + ath79_wdt_disable(); + else { + pr_crit(DRIVER_NAME ": device closed unexpectedly, " + "watchdog timer will not stop!\n"); + ath79_wdt_keepalive(); + } + + clear_bit(WDT_FLAGS_BUSY, &wdt_flags); + clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + + return 0; +} + +static ssize_t ath79_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + + if (c == 'V') + set_bit(WDT_FLAGS_EXPECT_CLOSE, + &wdt_flags); + } + } + + ath79_wdt_keepalive(); + } + + return len; +} + +static const struct watchdog_info ath79_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE | WDIOF_CARDRESET, + .firmware_version = 0, + .identity = "ATH79 watchdog", +}; + +static long ath79_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int err; + int t; + + switch (cmd) { + case WDIOC_GETSUPPORT: + err = copy_to_user(argp, &ath79_wdt_info, + sizeof(ath79_wdt_info)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + err = put_user(0, p); + break; + + case WDIOC_GETBOOTSTATUS: + err = put_user(boot_status, p); + break; + + case WDIOC_KEEPALIVE: + ath79_wdt_keepalive(); + err = 0; + break; + + case WDIOC_SETTIMEOUT: + err = get_user(t, p); + if (err) + break; + + err = ath79_wdt_set_timeout(t); + if (err) + break; + + /* fallthrough */ + case WDIOC_GETTIMEOUT: + err = put_user(timeout, p); + break; + + default: + err = -ENOTTY; + break; + } + + return err; +} + +static const struct file_operations ath79_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = ath79_wdt_write, + .unlocked_ioctl = ath79_wdt_ioctl, + .open = ath79_wdt_open, + .release = ath79_wdt_release, +}; + +static struct miscdevice ath79_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ath79_wdt_fops, +}; + +static int __devinit ath79_wdt_probe(struct platform_device *pdev) +{ + u32 ctrl; + int err; + + wdt_clk = clk_get(&pdev->dev, "wdt"); + if (IS_ERR(wdt_clk)) + return PTR_ERR(wdt_clk); + + err = clk_enable(wdt_clk); + if (err) + goto err_clk_put; + + wdt_freq = clk_get_rate(wdt_clk); + if (!wdt_freq) { + err = -EINVAL; + goto err_clk_disable; + } + + max_timeout = (0xfffffffful / wdt_freq); + if (timeout < 1 || timeout > max_timeout) { + timeout = max_timeout; + dev_info(&pdev->dev, + "timeout value must be 0 < timeout < %d, using %d\n", + max_timeout, timeout); + } + + ctrl = ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL); + boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0; + + err = misc_register(&ath79_wdt_miscdev); + if (err) { + dev_err(&pdev->dev, + "unable to register misc device, err=%d\n", err); + goto err_clk_disable; + } + + return 0; + +err_clk_disable: + clk_disable(wdt_clk); +err_clk_put: + clk_put(wdt_clk); + return err; +} + +static int __devexit ath79_wdt_remove(struct platform_device *pdev) +{ + misc_deregister(&ath79_wdt_miscdev); + clk_disable(wdt_clk); + clk_put(wdt_clk); + return 0; +} + +static void ath97_wdt_shutdown(struct platform_device *pdev) +{ + ath79_wdt_disable(); +} + +static struct platform_driver ath79_wdt_driver = { + .remove = __devexit_p(ath79_wdt_remove), + .shutdown = ath97_wdt_shutdown, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init ath79_wdt_init(void) +{ + return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe); +} +module_init(ath79_wdt_init); + +static void __exit ath79_wdt_exit(void) +{ + platform_driver_unregister(&ath79_wdt_driver); +} +module_exit(ath79_wdt_exit); + +MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver"); +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); +MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index d11ffb091b0d..7e7ec9c35b6a 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -85,6 +85,22 @@ static unsigned int sec_to_period(unsigned int secs) return 0; } +static void __booke_wdt_set(void *data) +{ + u32 val; + + val = mfspr(SPRN_TCR); + val &= ~WDTP_MASK; + val |= WDTP(booke_wdt_period); + + mtspr(SPRN_TCR, val); +} + +static void booke_wdt_set(void) +{ + on_each_cpu(__booke_wdt_set, NULL, 0); +} + static void __booke_wdt_ping(void *data) { mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); @@ -181,8 +197,7 @@ static long booke_wdt_ioctl(struct file *file, #else booke_wdt_period = tmp; #endif - mtspr(SPRN_TCR, (mfspr(SPRN_TCR) & ~WDTP_MASK) | - WDTP(booke_wdt_period)); + booke_wdt_set(); return 0; case WDIOC_GETTIMEOUT: return put_user(booke_wdt_period, p); @@ -193,8 +208,15 @@ static long booke_wdt_ioctl(struct file *file, return 0; } +/* wdt_is_active stores wether or not the /dev/watchdog device is opened */ +static unsigned long wdt_is_active; + static int booke_wdt_open(struct inode *inode, struct file *file) { + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &wdt_is_active)) + return -EBUSY; + spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 0) { booke_wdt_enabled = 1; @@ -210,8 +232,17 @@ static int booke_wdt_open(struct inode *inode, struct file *file) static int booke_wdt_release(struct inode *inode, struct file *file) { +#ifndef CONFIG_WATCHDOG_NOWAYOUT + /* Normally, the watchdog is disabled when /dev/watchdog is closed, but + * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the + * watchdog should remain enabled. So we disable it only if + * CONFIG_WATCHDOG_NOWAYOUT is not defined. + */ on_each_cpu(__booke_wdt_disable, NULL, 0); booke_wdt_enabled = 0; +#endif + + clear_bit(0, &wdt_is_active); return 0; } diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 65e579635dba..d4d8d1fdccc4 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -42,18 +42,21 @@ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ #define SIO_REG_DEVREV 0x22 /* Device revision */ #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ +#define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */ +#define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */ +#define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */ +#define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */ #define SIO_REG_ENABLE 0x30 /* Logical device enable */ #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ -#define SIO_F71808_ID 0x0901 /* Chipset ID */ -#define SIO_F71858_ID 0x0507 /* Chipset ID */ +#define SIO_F71808_ID 0x0901 /* Chipset ID */ +#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ +#define SIO_F71869_ID 0x0814 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71889_ID 0x0723 /* Chipset ID */ -#define F71882FG_REG_START 0x01 - #define F71808FG_REG_WDO_CONF 0xf0 #define F71808FG_REG_WDT_CONF 0xf5 #define F71808FG_REG_WD_TIME 0xf6 @@ -70,13 +73,15 @@ #define WATCHDOG_MAX_TIMEOUT (60 * 255) #define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for watchdog signal */ +#define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output + pin number 63 */ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); static const int max_timeout = WATCHDOG_MAX_TIMEOUT; -static int timeout = 60; /* default timeout in seconds */ +static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=" @@ -89,6 +94,12 @@ MODULE_PARM_DESC(pulse_width, "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms" " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); +static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN; +module_param(f71862fg_pin, uint, 0); +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; module_param(nowayout, bool, 0444); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); @@ -98,12 +109,13 @@ module_param(start_withtimeout, uint, 0); MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" " given initial timeout. Zero (default) disables this feature."); -enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg }; +enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg }; static const char *f71808e_names[] = { "f71808fg", "f71858fg", "f71862fg", + "f71869", "f71882fg", "f71889fg", }; @@ -282,6 +294,28 @@ exit_unlock: return err; } +static int f71862fg_pin_configure(unsigned short ioaddr) +{ + /* When ioaddr is non-zero the calling function has to take care of + mutex handling and superio preparation! */ + + if (f71862fg_pin == 63) { + if (ioaddr) { + /* SPI must be disabled first to use this pin! */ + superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6); + superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4); + } + } else if (f71862fg_pin == 56) { + if (ioaddr) + superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1); + } else { + printk(KERN_ERR DRVNAME ": Invalid argument f71862fg_pin=%d\n", + f71862fg_pin); + return -EINVAL; + } + return 0; +} + static int watchdog_start(void) { /* Make sure we don't die as soon as the watchdog is enabled below */ @@ -299,19 +333,30 @@ static int watchdog_start(void) switch (watchdog.type) { case f71808fg: /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */ - superio_clear_bit(watchdog.sioaddr, 0x2a, 3); - superio_clear_bit(watchdog.sioaddr, 0x2b, 3); + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT2, 3); + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 3); + break; + + case f71862fg: + err = f71862fg_pin_configure(watchdog.sioaddr); + if (err) + goto exit_superio; + break; + + case f71869: + /* GPIO14 --> WDTRST# */ + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4); break; case f71882fg: /* Set pin 56 to WDTRST# */ - superio_set_bit(watchdog.sioaddr, 0x29, 1); + superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1); break; case f71889fg: /* set pin 40 to WDTRST# */ - superio_outb(watchdog.sioaddr, 0x2b, - superio_inb(watchdog.sioaddr, 0x2b) & 0xcf); + superio_outb(watchdog.sioaddr, SIO_REG_MFUNCT3, + superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf); break; default: @@ -711,16 +756,19 @@ static int __init f71808e_find(int sioaddr) case SIO_F71808_ID: watchdog.type = f71808fg; break; + case SIO_F71862_ID: + watchdog.type = f71862fg; + err = f71862fg_pin_configure(0); /* validate module parameter */ + break; + case SIO_F71869_ID: + watchdog.type = f71869; + break; case SIO_F71882_ID: watchdog.type = f71882fg; break; case SIO_F71889_ID: watchdog.type = f71889fg; break; - case SIO_F71862_ID: - /* These have a watchdog, though it isn't implemented (yet). */ - err = -ENOSYS; - goto exit; case SIO_F71858_ID: /* Confirmed (by datasheet) not to have a watchdog. */ err = -ENODEV; diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index b8838d2c67a6..2c6c2b4ad8bf 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -1,7 +1,7 @@ /* * intel TCO Watchdog Driver * - * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. + * (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,13 +26,15 @@ * document number 301473-002, 301474-026: 82801F (ICH6) * document number 313082-001, 313075-006: 631xESB, 632xESB * document number 307013-003, 307014-024: 82801G (ICH7) + * document number 322896-001, 322897-001: NM10 * document number 313056-003, 313057-017: 82801H (ICH8) * document number 316972-004, 316973-012: 82801I (ICH9) * document number 319973-002, 319974-002: 82801J (ICH10) * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) * document number 320066-003, 320257-008: EP80597 (IICH) - * document number TBD : Cougar Point (CPT) + * document number 324645-001, 324646-001: Cougar Point (CPT) * document number TBD : Patsburg (PBG) + * document number TBD : DH89xxCC */ /* @@ -85,6 +87,7 @@ enum iTCO_chipsets { TCO_ICH7DH, /* ICH7DH */ TCO_ICH7M, /* ICH7-M & ICH7-U */ TCO_ICH7MDH, /* ICH7-M DH */ + TCO_NM10, /* NM10 */ TCO_ICH8, /* ICH8 & ICH8R */ TCO_ICH8DH, /* ICH8DH */ TCO_ICH8DO, /* ICH8DO */ @@ -149,6 +152,7 @@ enum iTCO_chipsets { TCO_CPT31, /* Cougar Point */ TCO_PBG1, /* Patsburg */ TCO_PBG2, /* Patsburg */ + TCO_DH89XXCC, /* DH89xxCC */ }; static struct { @@ -174,6 +178,7 @@ static struct { {"ICH7DH", 2}, {"ICH7-M or ICH7-U", 2}, {"ICH7-M DH", 2}, + {"NM10", 2}, {"ICH8 or ICH8R", 2}, {"ICH8DH", 2}, {"ICH8DO", 2}, @@ -238,6 +243,7 @@ static struct { {"Cougar Point", 2}, {"Patsburg", 2}, {"Patsburg", 2}, + {"DH89xxCC", 2}, {NULL, 0} }; @@ -291,6 +297,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, + { ITCO_PCI_DEVICE(0x27bc, TCO_NM10)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, @@ -355,6 +362,7 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, + { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index 2852bb2e3fd9..811471903e8a 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c @@ -21,7 +21,7 @@ #include <linux/watchdog.h> #include <linux/io.h> #include <linux/uaccess.h> -#include <mach/timex.h> +#include <mach/hardware.h> #include <mach/regs-timer.h> #define WDT_DEFAULT_TIME 5 /* seconds */ diff --git a/drivers/watchdog/m548x_wdt.c b/drivers/watchdog/m548x_wdt.c new file mode 100644 index 000000000000..cabbcfe1c847 --- /dev/null +++ b/drivers/watchdog/m548x_wdt.c @@ -0,0 +1,227 @@ +/* + * drivers/watchdog/m548x_wdt.c + * + * Watchdog driver for ColdFire MCF548x processors + * Copyright 2010 (c) Philippe De Muyter <phdm@macqel.be> + * + * Adapted from the IXP4xx watchdog driver, which carries these notices: + * + * Author: Deepak Saxena <dsaxena@plexity.net> + * + * Copyright 2004 (c) MontaVista, Software, Inc. + * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/ioport.h> +#include <linux/uaccess.h> + +#include <asm/coldfire.h> +#include <asm/m548xsim.h> +#include <asm/m548xgpt.h> + +static int nowayout = WATCHDOG_NOWAYOUT; +static unsigned int heartbeat = 30; /* (secs) Default is 0.5 minute */ +static unsigned long wdt_status; + +#define WDT_IN_USE 0 +#define WDT_OK_TO_CLOSE 1 + +static void wdt_enable(void) +{ + unsigned int gms0; + + /* preserve GPIO usage, if any */ + gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0); + if (gms0 & MCF_GPT_GMS_TMS_GPIO) + gms0 &= (MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_GPIO_MASK + | MCF_GPT_GMS_OD); + else + gms0 = MCF_GPT_GMS_TMS_GPIO | MCF_GPT_GMS_OD; + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); + __raw_writel(MCF_GPT_GCIR_PRE(heartbeat*(MCF_BUSCLK/0xffff)) | + MCF_GPT_GCIR_CNT(0xffff), MCF_MBAR + MCF_GPT_GCIR0); + gms0 |= MCF_GPT_GMS_OCPW(0xA5) | MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE; + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); +} + +static void wdt_disable(void) +{ + unsigned int gms0; + + /* disable watchdog */ + gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0); + gms0 &= ~(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE); + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); +} + +static void wdt_keepalive(void) +{ + unsigned int gms0; + + gms0 = __raw_readl(MCF_MBAR + MCF_GPT_GMS0); + gms0 |= MCF_GPT_GMS_OCPW(0xA5); + __raw_writel(gms0, MCF_MBAR + MCF_GPT_GMS0); +} + +static int m548x_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(WDT_IN_USE, &wdt_status)) + return -EBUSY; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + wdt_enable(); + return nonseekable_open(inode, file); +} + +static ssize_t m548x_wdt_write(struct file *file, const char *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + for (i = 0; i != len; i++) { + char c; + + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + set_bit(WDT_OK_TO_CLOSE, &wdt_status); + } + } + wdt_keepalive(); + } + return len; +} + +static const struct watchdog_info ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING, + .identity = "Coldfire M548x Watchdog", +}; + +static long m548x_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret = -ENOTTY; + int time; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ret = copy_to_user((struct watchdog_info *)arg, &ident, + sizeof(ident)) ? -EFAULT : 0; + break; + + case WDIOC_GETSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, (int *)arg); + break; + + case WDIOC_KEEPALIVE: + wdt_keepalive(); + ret = 0; + break; + + case WDIOC_SETTIMEOUT: + ret = get_user(time, (int *)arg); + if (ret) + break; + + if (time <= 0 || time > 30) { + ret = -EINVAL; + break; + } + + heartbeat = time; + wdt_enable(); + /* Fall through */ + + case WDIOC_GETTIMEOUT: + ret = put_user(heartbeat, (int *)arg); + break; + } + return ret; +} + +static int m548x_wdt_release(struct inode *inode, struct file *file) +{ + if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) + wdt_disable(); + else { + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " + "timer will not stop\n"); + wdt_keepalive(); + } + clear_bit(WDT_IN_USE, &wdt_status); + clear_bit(WDT_OK_TO_CLOSE, &wdt_status); + + return 0; +} + + +static const struct file_operations m548x_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = m548x_wdt_write, + .unlocked_ioctl = m548x_wdt_ioctl, + .open = m548x_wdt_open, + .release = m548x_wdt_release, +}; + +static struct miscdevice m548x_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &m548x_wdt_fops, +}; + +static int __init m548x_wdt_init(void) +{ + if (!request_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4, + "Coldfire M548x Watchdog")) { + printk(KERN_WARNING + "Coldfire M548x Watchdog : I/O region busy\n"); + return -EBUSY; + } + printk(KERN_INFO "ColdFire watchdog driver is loaded.\n"); + + return misc_register(&m548x_wdt_miscdev); +} + +static void __exit m548x_wdt_exit(void) +{ + misc_deregister(&m548x_wdt_miscdev); + release_mem_region(MCF_MBAR + MCF_GPT_GCIR0, 4); +} + +module_init(m548x_wdt_init); +module_exit(m548x_wdt_exit); + +MODULE_AUTHOR("Philippe De Muyter <phdm@macqel.be>"); +MODULE_DESCRIPTION("Coldfire M548x Watchdog"); + +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 30s)"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c new file mode 100644 index 000000000000..1a50aa7079bf --- /dev/null +++ b/drivers/watchdog/nv_tco.c @@ -0,0 +1,512 @@ +/* + * nv_tco 0.01: TCO timer driver for NV chipsets + * + * (c) Copyright 2005 Google Inc., All Rights Reserved. + * + * Based off i8xx_tco.c: + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights + * Reserved. + * http://www.kernelconcepts.de + * + * 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. + * + * TCO timer driver for NV chipsets + * based on softdog.c by Alan Cox <alan@redhat.com> + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/io.h> + +#include "nv_tco.h" + +/* Module and version information */ +#define TCO_VERSION "0.01" +#define TCO_MODULE_NAME "NV_TCO" +#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION +#define PFX TCO_MODULE_NAME ": " + +/* internal variables */ +static unsigned int tcobase; +static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ +static unsigned long timer_alive; +static char tco_expect_close; +static struct pci_dev *tco_pci; + +/* the watchdog platform device */ +static struct platform_device *nv_tco_platform_device; + +/* module parameters */ +#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2<heartbeat<39) */ +static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, " + "default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" + " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +/* + * Some TCO specific functions + */ +static inline unsigned char seconds_to_ticks(int seconds) +{ + /* the internal timer is stored as ticks which decrement + * every 0.6 seconds */ + return (seconds * 10) / 6; +} + +static void tco_timer_start(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = inl(TCO_CNT(tcobase)); + val &= ~TCO_CNT_TCOHALT; + outl(val, TCO_CNT(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static void tco_timer_stop(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = inl(TCO_CNT(tcobase)); + val |= TCO_CNT_TCOHALT; + outl(val, TCO_CNT(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static void tco_timer_keepalive(void) +{ + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + outb(0x01, TCO_RLD(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static int tco_timer_set_heartbeat(int t) +{ + int ret = 0; + unsigned char tmrval; + unsigned long flags; + u8 val; + + /* + * note seconds_to_ticks(t) > t, so if t > 0x3f, so is + * tmrval=seconds_to_ticks(t). Check that the count in seconds isn't + * out of range on it's own (to avoid overflow in tmrval). + */ + if (t < 0 || t > 0x3f) + return -EINVAL; + tmrval = seconds_to_ticks(t); + + /* "Values of 0h-3h are ignored and should not be attempted" */ + if (tmrval > 0x3f || tmrval < 0x04) + return -EINVAL; + + /* Write new heartbeat to watchdog */ + spin_lock_irqsave(&tco_lock, flags); + val = inb(TCO_TMR(tcobase)); + val &= 0xc0; + val |= tmrval; + outb(val, TCO_TMR(tcobase)); + val = inb(TCO_TMR(tcobase)); + + if ((val & 0x3f) != tmrval) + ret = -EINVAL; + spin_unlock_irqrestore(&tco_lock, flags); + + if (ret) + return ret; + + heartbeat = t; + return 0; +} + +/* + * /dev/watchdog handling + */ + +static int nv_tco_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* Reload and activate timer */ + tco_timer_keepalive(); + tco_timer_start(); + return nonseekable_open(inode, file); +} + +static int nv_tco_release(struct inode *inode, struct file *file) +{ + /* Shut off the timer */ + if (tco_expect_close == 42) { + tco_timer_stop(); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping " + "watchdog!\n"); + tco_timer_keepalive(); + } + clear_bit(0, &timer_alive); + tco_expect_close = 0; + return 0; +} + +static ssize_t nv_tco_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* + * note: just in case someone wrote the magic character + * five months ago... + */ + tco_expect_close = 0; + + /* + * scan to see whether or not we got the magic + * character + */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + tco_expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + tco_timer_keepalive(); + } + return len; +} + +static long nv_tco_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_options, retval = -EINVAL; + int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; + static const struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = TCO_MODULE_NAME, + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_SETOPTIONS: + if (get_user(new_options, p)) + return -EFAULT; + if (new_options & WDIOS_DISABLECARD) { + tco_timer_stop(); + retval = 0; + } + if (new_options & WDIOS_ENABLECARD) { + tco_timer_keepalive(); + tco_timer_start(); + retval = 0; + } + return retval; + case WDIOC_KEEPALIVE: + tco_timer_keepalive(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_heartbeat, p)) + return -EFAULT; + if (tco_timer_set_heartbeat(new_heartbeat)) + return -EINVAL; + tco_timer_keepalive(); + /* Fall through */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + default: + return -ENOTTY; + } +} + +/* + * Kernel Interfaces + */ + +static const struct file_operations nv_tco_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = nv_tco_write, + .unlocked_ioctl = nv_tco_ioctl, + .open = nv_tco_open, + .release = nv_tco_release, +}; + +static struct miscdevice nv_tco_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &nv_tco_fops, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id tco_pci_tbl[] = { + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE(pci, tco_pci_tbl); + +/* + * Init & exit routines + */ + +static unsigned char __init nv_tco_getdevice(void) +{ + struct pci_dev *dev = NULL; + u32 val; + + /* Find the PCI device */ + for_each_pci_dev(dev) { + if (pci_match_id(tco_pci_tbl, dev) != NULL) { + tco_pci = dev; + break; + } + } + + if (!tco_pci) + return 0; + + /* Find the base io port */ + pci_read_config_dword(tco_pci, 0x64, &val); + val &= 0xffff; + if (val == 0x0001 || val == 0x0000) { + /* Something is wrong here, bar isn't setup */ + printk(KERN_ERR PFX "failed to get tcobase address\n"); + return 0; + } + val &= 0xff00; + tcobase = val + 0x40; + + if (!request_region(tcobase, 0x10, "NV TCO")) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + tcobase); + return 0; + } + + /* Set a reasonable heartbeat before we stop the timer */ + tco_timer_set_heartbeat(30); + + /* + * Stop the TCO before we change anything so we don't race with + * a zeroed timer. + */ + tco_timer_keepalive(); + tco_timer_stop(); + + /* Disable SMI caused by TCO */ + if (!request_region(MCP51_SMI_EN(tcobase), 4, "NV TCO")) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + MCP51_SMI_EN(tcobase)); + goto out; + } + val = inl(MCP51_SMI_EN(tcobase)); + val &= ~MCP51_SMI_EN_TCO; + outl(val, MCP51_SMI_EN(tcobase)); + val = inl(MCP51_SMI_EN(tcobase)); + release_region(MCP51_SMI_EN(tcobase), 4); + if (val & MCP51_SMI_EN_TCO) { + printk(KERN_ERR PFX "Could not disable SMI caused by TCO\n"); + goto out; + } + + /* Check chipset's NO_REBOOT bit */ + pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); + val |= MCP51_SMBUS_SETUP_B_TCO_REBOOT; + pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val); + pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); + if (!(val & MCP51_SMBUS_SETUP_B_TCO_REBOOT)) { + printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot " + "disabled by hardware\n"); + goto out; + } + + return 1; +out: + release_region(tcobase, 0x10); + return 0; +} + +static int __devinit nv_tco_init(struct platform_device *dev) +{ + int ret; + + /* Check whether or not the hardware watchdog is there */ + if (!nv_tco_getdevice()) + return -ENODEV; + + /* Check to see if last reboot was due to watchdog timeout */ + printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n", + inl(TCO_STS(tcobase)) & TCO_STS_TCO2TO_STS ? "" : "not "); + + /* Clear out the old status */ + outl(TCO_STS_RESET, TCO_STS(tcobase)); + + /* + * Check that the heartbeat value is within it's range. + * If not, reset to the default. + */ + if (tco_timer_set_heartbeat(heartbeat)) { + heartbeat = WATCHDOG_HEARTBEAT; + tco_timer_set_heartbeat(heartbeat); + printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, " + "using %d\n", heartbeat); + } + + ret = misc_register(&nv_tco_miscdev); + if (ret != 0) { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d " + "(err=%d)\n", WATCHDOG_MINOR, ret); + goto unreg_region; + } + + clear_bit(0, &timer_alive); + + tco_timer_stop(); + + printk(KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec " + "(nowayout=%d)\n", tcobase, heartbeat, nowayout); + + return 0; + +unreg_region: + release_region(tcobase, 0x10); + return ret; +} + +static void __devexit nv_tco_cleanup(void) +{ + u32 val; + + /* Stop the timer before we leave */ + if (!nowayout) + tco_timer_stop(); + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); + val &= ~MCP51_SMBUS_SETUP_B_TCO_REBOOT; + pci_write_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, val); + pci_read_config_dword(tco_pci, MCP51_SMBUS_SETUP_B, &val); + if (val & MCP51_SMBUS_SETUP_B_TCO_REBOOT) { + printk(KERN_CRIT PFX "Couldn't unset REBOOT bit. Machine may " + "soon reset\n"); + } + + /* Deregister */ + misc_deregister(&nv_tco_miscdev); + release_region(tcobase, 0x10); +} + +static int __devexit nv_tco_remove(struct platform_device *dev) +{ + if (tcobase) + nv_tco_cleanup(); + + return 0; +} + +static void nv_tco_shutdown(struct platform_device *dev) +{ + tco_timer_stop(); +} + +static struct platform_driver nv_tco_driver = { + .probe = nv_tco_init, + .remove = __devexit_p(nv_tco_remove), + .shutdown = nv_tco_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = TCO_MODULE_NAME, + }, +}; + +static int __init nv_tco_init_module(void) +{ + int err; + + printk(KERN_INFO PFX "NV TCO WatchDog Timer Driver v%s\n", + TCO_VERSION); + + err = platform_driver_register(&nv_tco_driver); + if (err) + return err; + + nv_tco_platform_device = platform_device_register_simple( + TCO_MODULE_NAME, -1, NULL, 0); + if (IS_ERR(nv_tco_platform_device)) { + err = PTR_ERR(nv_tco_platform_device); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&nv_tco_driver); + return err; +} + +static void __exit nv_tco_cleanup_module(void) +{ + platform_device_unregister(nv_tco_platform_device); + platform_driver_unregister(&nv_tco_driver); + printk(KERN_INFO PFX "NV TCO Watchdog Module Unloaded.\n"); +} + +module_init(nv_tco_init_module); +module_exit(nv_tco_cleanup_module); + +MODULE_AUTHOR("Mike Waychison"); +MODULE_DESCRIPTION("TCO timer driver for NV chipsets"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/nv_tco.h b/drivers/watchdog/nv_tco.h new file mode 100644 index 000000000000..c2d1d04e055b --- /dev/null +++ b/drivers/watchdog/nv_tco.h @@ -0,0 +1,64 @@ +/* + * nv_tco: TCO timer driver for nVidia chipsets. + * + * (c) Copyright 2005 Google Inc., All Rights Reserved. + * + * Supported Chipsets: + * - MCP51/MCP55 + * + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights + * Reserved. + * http://www.kernelconcepts.de + * + * 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. + * + * Neither kernel concepts nor Nils Faerber admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de> + * developed for + * Jentro AG, Haar/Munich (Germany) + * + * TCO timer driver for NV chipsets + * based on softdog.c by Alan Cox <alan@redhat.com> + */ + +/* + * Some address definitions for the TCO + */ + +#define TCO_RLD(base) ((base) + 0x00) /* TCO Timer Reload and Current Value */ +#define TCO_TMR(base) ((base) + 0x01) /* TCO Timer Initial Value */ + +#define TCO_STS(base) ((base) + 0x04) /* TCO Status Register */ +/* + * TCO Boot Status bit: set on TCO reset, reset by software or standby + * power-good (survives reboots), unfortunately this bit is never + * set. + */ +# define TCO_STS_BOOT_STS (1 << 9) +/* + * first and 2nd timeout status bits, these also survive a warm boot, + * and they work, so we use them. + */ +# define TCO_STS_TCO_INT_STS (1 << 1) +# define TCO_STS_TCO2TO_STS (1 << 10) +# define TCO_STS_RESET (TCO_STS_BOOT_STS | TCO_STS_TCO2TO_STS | \ + TCO_STS_TCO_INT_STS) + +#define TCO_CNT(base) ((base) + 0x08) /* TCO Control Register */ +# define TCO_CNT_TCOHALT (1 << 12) + +#define MCP51_SMBUS_SETUP_B 0xe8 +# define MCP51_SMBUS_SETUP_B_TCO_REBOOT (1 << 25) + +/* + * The SMI_EN register is at the base io address + 0x04, + * while TCOBASE is + 0x40. + */ +#define MCP51_SMI_EN(base) ((base) - 0x40 + 0x04) +# define MCP51_SMI_EN_TCO ((1 << 4) | (1 << 5)) diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c new file mode 100644 index 000000000000..808372883e88 --- /dev/null +++ b/drivers/watchdog/sp5100_tco.c @@ -0,0 +1,480 @@ +/* + * sp5100_tco : TCO timer driver for sp5100 chipsets + * + * (c) Copyright 2009 Google Inc., All Rights Reserved. + * + * Based on i8xx_tco.c: + * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights + * Reserved. + * http://www.kernelconcepts.de + * + * 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. + * + * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide" + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/io.h> + +#include "sp5100_tco.h" + +/* Module and version information */ +#define TCO_VERSION "0.01" +#define TCO_MODULE_NAME "SP5100 TCO timer" +#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION +#define PFX TCO_MODULE_NAME ": " + +/* internal variables */ +static void __iomem *tcobase; +static unsigned int pm_iobase; +static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ +static unsigned long timer_alive; +static char tco_expect_close; +static struct pci_dev *sp5100_tco_pci; + +/* the watchdog platform device */ +static struct platform_device *sp5100_tco_platform_device; + +/* module parameters */ + +#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat. */ +static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default=" + __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" + " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +/* + * Some TCO specific functions + */ +static void tco_timer_start(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = readl(SP5100_WDT_CONTROL(tcobase)); + val |= SP5100_WDT_START_STOP_BIT; + writel(val, SP5100_WDT_CONTROL(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static void tco_timer_stop(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = readl(SP5100_WDT_CONTROL(tcobase)); + val &= ~SP5100_WDT_START_STOP_BIT; + writel(val, SP5100_WDT_CONTROL(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static void tco_timer_keepalive(void) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&tco_lock, flags); + val = readl(SP5100_WDT_CONTROL(tcobase)); + val |= SP5100_WDT_TRIGGER_BIT; + writel(val, SP5100_WDT_CONTROL(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); +} + +static int tco_timer_set_heartbeat(int t) +{ + unsigned long flags; + + if (t < 0 || t > 0xffff) + return -EINVAL; + + /* Write new heartbeat to watchdog */ + spin_lock_irqsave(&tco_lock, flags); + writel(t, SP5100_WDT_COUNT(tcobase)); + spin_unlock_irqrestore(&tco_lock, flags); + + heartbeat = t; + return 0; +} + +/* + * /dev/watchdog handling + */ + +static int sp5100_tco_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* Reload and activate timer */ + tco_timer_start(); + tco_timer_keepalive(); + return nonseekable_open(inode, file); +} + +static int sp5100_tco_release(struct inode *inode, struct file *file) +{ + /* Shut off the timer. */ + if (tco_expect_close == 42) { + tco_timer_stop(); + } else { + printk(KERN_CRIT PFX + "Unexpected close, not stopping watchdog!\n"); + tco_timer_keepalive(); + } + clear_bit(0, &timer_alive); + tco_expect_close = 0; + return 0; +} + +static ssize_t sp5100_tco_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* note: just in case someone wrote the magic character + * five months ago... */ + tco_expect_close = 0; + + /* scan to see whether or not we got the magic character + */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + tco_expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + tco_timer_keepalive(); + } + return len; +} + +static long sp5100_tco_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_options, retval = -EINVAL; + int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; + static const struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = TCO_MODULE_NAME, + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, + sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_SETOPTIONS: + if (get_user(new_options, p)) + return -EFAULT; + if (new_options & WDIOS_DISABLECARD) { + tco_timer_stop(); + retval = 0; + } + if (new_options & WDIOS_ENABLECARD) { + tco_timer_start(); + tco_timer_keepalive(); + retval = 0; + } + return retval; + case WDIOC_KEEPALIVE: + tco_timer_keepalive(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_heartbeat, p)) + return -EFAULT; + if (tco_timer_set_heartbeat(new_heartbeat)) + return -EINVAL; + tco_timer_keepalive(); + /* Fall through */ + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + default: + return -ENOTTY; + } +} + +/* + * Kernel Interfaces + */ + +static const struct file_operations sp5100_tco_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = sp5100_tco_write, + .unlocked_ioctl = sp5100_tco_ioctl, + .open = sp5100_tco_open, + .release = sp5100_tco_release, +}; + +static struct miscdevice sp5100_tco_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &sp5100_tco_fops, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might + * want to register another driver on the same PCI id. + */ +static struct pci_device_id sp5100_tco_pci_tbl[] = { + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID, + PCI_ANY_ID, }, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl); + +/* + * Init & exit routines + */ + +static unsigned char __devinit sp5100_tco_setupdevice(void) +{ + struct pci_dev *dev = NULL; + u32 val; + + /* Match the PCI device */ + for_each_pci_dev(dev) { + if (pci_match_id(sp5100_tco_pci_tbl, dev) != NULL) { + sp5100_tco_pci = dev; + break; + } + } + + if (!sp5100_tco_pci) + return 0; + + /* Request the IO ports used by this driver */ + pm_iobase = SP5100_IO_PM_INDEX_REG; + if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + pm_iobase); + goto exit; + } + + /* Find the watchdog base address. */ + outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG); + val = inb(SP5100_IO_PM_DATA_REG); + outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG); + val = val << 8 | inb(SP5100_IO_PM_DATA_REG); + outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG); + val = val << 8 | inb(SP5100_IO_PM_DATA_REG); + outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG); + /* Low three bits of BASE0 are reserved. */ + val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); + + tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); + if (tcobase == 0) { + printk(KERN_ERR PFX "failed to get tcobase address\n"); + goto unreg_region; + } + + /* Enable watchdog decode bit */ + pci_read_config_dword(sp5100_tco_pci, + SP5100_PCI_WATCHDOG_MISC_REG, + &val); + + val |= SP5100_PCI_WATCHDOG_DECODE_EN; + + pci_write_config_dword(sp5100_tco_pci, + SP5100_PCI_WATCHDOG_MISC_REG, + val); + + /* Enable Watchdog timer and set the resolution to 1 sec. */ + outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); + val = inb(SP5100_IO_PM_DATA_REG); + val |= SP5100_PM_WATCHDOG_SECOND_RES; + val &= ~SP5100_PM_WATCHDOG_DISABLE; + outb(val, SP5100_IO_PM_DATA_REG); + + /* Check that the watchdog action is set to reset the system. */ + val = readl(SP5100_WDT_CONTROL(tcobase)); + val &= ~SP5100_PM_WATCHDOG_ACTION_RESET; + writel(val, SP5100_WDT_CONTROL(tcobase)); + + /* Set a reasonable heartbeat before we stop the timer */ + tco_timer_set_heartbeat(heartbeat); + + /* + * Stop the TCO before we change anything so we don't race with + * a zeroed timer. + */ + tco_timer_stop(); + + /* Done */ + return 1; + + iounmap(tcobase); +unreg_region: + release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); +exit: + return 0; +} + +static int __devinit sp5100_tco_init(struct platform_device *dev) +{ + int ret; + u32 val; + + /* Check whether or not the hardware watchdog is there. If found, then + * set it up. + */ + if (!sp5100_tco_setupdevice()) + return -ENODEV; + + /* Check to see if last reboot was due to watchdog timeout */ + printk(KERN_INFO PFX "Watchdog reboot %sdetected.\n", + readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ? + "" : "not "); + + /* Clear out the old status */ + val = readl(SP5100_WDT_CONTROL(tcobase)); + val &= ~SP5100_PM_WATCHDOG_FIRED; + writel(val, SP5100_WDT_CONTROL(tcobase)); + + /* + * Check that the heartbeat value is within it's range. + * If not, reset to the default. + */ + if (tco_timer_set_heartbeat(heartbeat)) { + heartbeat = WATCHDOG_HEARTBEAT; + tco_timer_set_heartbeat(heartbeat); + } + + ret = misc_register(&sp5100_tco_miscdev); + if (ret != 0) { + printk(KERN_ERR PFX "cannot register miscdev on minor=" + "%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto exit; + } + + clear_bit(0, &timer_alive); + + printk(KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec" + " (nowayout=%d)\n", + tcobase, heartbeat, nowayout); + + return 0; + +exit: + iounmap(tcobase); + release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); + return ret; +} + +static void __devexit sp5100_tco_cleanup(void) +{ + /* Stop the timer before we leave */ + if (!nowayout) + tco_timer_stop(); + + /* Deregister */ + misc_deregister(&sp5100_tco_miscdev); + iounmap(tcobase); + release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); +} + +static int __devexit sp5100_tco_remove(struct platform_device *dev) +{ + if (tcobase) + sp5100_tco_cleanup(); + return 0; +} + +static void sp5100_tco_shutdown(struct platform_device *dev) +{ + tco_timer_stop(); +} + +static struct platform_driver sp5100_tco_driver = { + .probe = sp5100_tco_init, + .remove = __devexit_p(sp5100_tco_remove), + .shutdown = sp5100_tco_shutdown, + .driver = { + .owner = THIS_MODULE, + .name = TCO_MODULE_NAME, + }, +}; + +static int __init sp5100_tco_init_module(void) +{ + int err; + + printk(KERN_INFO PFX "SP5100 TCO WatchDog Timer Driver v%s\n", + TCO_VERSION); + + err = platform_driver_register(&sp5100_tco_driver); + if (err) + return err; + + sp5100_tco_platform_device = platform_device_register_simple( + TCO_MODULE_NAME, -1, NULL, 0); + if (IS_ERR(sp5100_tco_platform_device)) { + err = PTR_ERR(sp5100_tco_platform_device); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&sp5100_tco_driver); + return err; +} + +static void __exit sp5100_tco_cleanup_module(void) +{ + platform_device_unregister(sp5100_tco_platform_device); + platform_driver_unregister(&sp5100_tco_driver); + printk(KERN_INFO PFX "SP5100 TCO Watchdog Module Unloaded.\n"); +} + +module_init(sp5100_tco_init_module); +module_exit(sp5100_tco_cleanup_module); + +MODULE_AUTHOR("Priyanka Gupta"); +MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h new file mode 100644 index 000000000000..a5a16cc90a34 --- /dev/null +++ b/drivers/watchdog/sp5100_tco.h @@ -0,0 +1,41 @@ +/* + * sp5100_tco: TCO timer driver for sp5100 chipsets. + * + * (c) Copyright 2009 Google Inc., All Rights Reserved. + * + * TCO timer driver for sp5100 chipsets + */ + +/* + * Some address definitions for the Watchdog + */ + +#define SP5100_WDT_MEM_MAP_SIZE 0x08 +#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */ +#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */ + +#define SP5100_WDT_START_STOP_BIT 1 +#define SP5100_WDT_TRIGGER_BIT (1 << 7) + +#define SP5100_PCI_WATCHDOG_MISC_REG 0x41 +#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3) + +#define SP5100_PM_IOPORTS_SIZE 0x02 + +/* These two IO registers are hardcoded and there doesn't seem to be a way to + * read them from a register. + */ +#define SP5100_IO_PM_INDEX_REG 0xCD6 +#define SP5100_IO_PM_DATA_REG 0xCD7 + +#define SP5100_PM_WATCHDOG_CONTROL 0x69 +#define SP5100_PM_WATCHDOG_BASE0 0x6C +#define SP5100_PM_WATCHDOG_BASE1 0x6D +#define SP5100_PM_WATCHDOG_BASE2 0x6E +#define SP5100_PM_WATCHDOG_BASE3 0x6F + +#define SP5100_PM_WATCHDOG_FIRED (1 << 1) +#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2) + +#define SP5100_PM_WATCHDOG_DISABLE 1 +#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1) diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 0f5288df0091..e5c91d4404ed 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -42,7 +42,7 @@ #include <asm/system.h> -#define WATCHDOG_NAME "w83627hf/thf/hg WDT" +#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" #define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ @@ -89,7 +89,7 @@ static void w83627hf_select_wd_register(void) c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ outb_p(0x2b, WDT_EFER); outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */ - } else if (c == 0x88) { /* W83627EHF */ + } else if (c == 0x88 || c == 0xa0) { /* W83627EHF / W83627DHG */ outb_p(0x2d, WDT_EFER); /* select GPIO5 */ c = inb_p(WDT_EFDR) & ~0x01; /* PIN77 -> WDT0# */ outb_p(0x2d, WDT_EFER); @@ -129,6 +129,8 @@ static void w83627hf_init(void) t = inb_p(WDT_EFDR); /* read CRF5 */ t &= ~0x0C; /* set second mode & disable keyboard turning off watchdog */ + t |= 0x02; /* enable the WDTO# output low pulse + to the KBRST# pin (PIN60) */ outb_p(t, WDT_EFDR); /* Write back to CRF5 */ outb_p(0xF7, WDT_EFER); /* Select CRF7 */ @@ -321,7 +323,7 @@ static int __init wdt_init(void) { int ret; - printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n"); + printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising.\n"); if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); |