From: Linus Torvalds Date: Mon, 21 Apr 2008 23:36:46 +0000 (-0700) Subject: Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/juhl/trivial X-Git-Tag: v2.6.26-rc1~1114 X-Git-Url: http://git.cascardo.info/?a=commitdiff_plain;h=e9b62693ae0a1e13ccc97a6792d9a7770c8d1b5b;p=cascardo%2Flinux.git Merge branch 'for-linus' of git://git./linux/kernel/git/juhl/trivial * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/juhl/trivial: (24 commits) DOC: A couple corrections and clarifications in USB doc. Generate a slightly more informative error msg for bad HZ fix typo "is" -> "if" in Makefile ext*: spelling fix prefered -> preferred DOCUMENTATION: Use newer DEFINE_SPINLOCK macro in docs. KEYS: Fix the comment to match the file name in rxrpc-type.h. RAID: remove trailing space from printk line DMA engine: typo fixes Remove unused MAX_NODES_SHIFT MAINTAINERS: Clarify access to OCFS2 development mailing list. V4L: Storage class should be before const qualifier (sn9c102) V4L: Storage class should be before const qualifier sonypi: Storage class should be before const qualifier intel_menlow: Storage class should be before const qualifier DVB: Storage class should be before const qualifier arm: Storage class should be before const qualifier ALSA: Storage class should be before const qualifier acpi: Storage class should be before const qualifier firmware_sample_driver.c: fix coding style MAINTAINERS: Add ati_remote2 driver ... Fixed up trivial conflicts in firmware_sample_driver.c --- e9b62693ae0a1e13ccc97a6792d9a7770c8d1b5b diff --cc arch/arm/mach-pxa/mfp-pxa3xx.c index b84c3ba7a8d6,000000000000..3a5b0fcbaf1f mode 100644,000000..100644 --- a/arch/arm/mach-pxa/mfp-pxa3xx.c +++ b/arch/arm/mach-pxa/mfp-pxa3xx.c @@@ -1,255 -1,0 +1,255 @@@ +/* + * linux/arch/arm/mach-pxa/mfp.c + * + * PXA3xx Multi-Function Pin Support + * + * Copyright (C) 2007 Marvell Internation Ltd. + * + * 2007-08-21: eric miao + * initial version + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* mfp_spin_lock is used to ensure that MFP register configuration + * (most likely a read-modify-write operation) is atomic, and that + * mfp_table[] is consistent + */ +static DEFINE_SPINLOCK(mfp_spin_lock); + +static void __iomem *mfpr_mmio_base = (void __iomem *)&__REG(MFPR_BASE); + +struct pxa3xx_mfp_pin { + unsigned long config; /* -1 for not configured */ + unsigned long mfpr_off; /* MFPRxx Register offset */ + unsigned long mfpr_run; /* Run-Mode Register Value */ + unsigned long mfpr_lpm; /* Low Power Mode Register Value */ +}; + +static struct pxa3xx_mfp_pin mfp_table[MFP_PIN_MAX]; + +/* mapping of MFP_LPM_* definitions to MFPR_LPM_* register bits */ - const static unsigned long mfpr_lpm[] = { ++static const unsigned long mfpr_lpm[] = { + MFPR_LPM_INPUT, + MFPR_LPM_DRIVE_LOW, + MFPR_LPM_DRIVE_HIGH, + MFPR_LPM_PULL_LOW, + MFPR_LPM_PULL_HIGH, + MFPR_LPM_FLOAT, +}; + +/* mapping of MFP_PULL_* definitions to MFPR_PULL_* register bits */ - const static unsigned long mfpr_pull[] = { ++static const unsigned long mfpr_pull[] = { + MFPR_PULL_NONE, + MFPR_PULL_LOW, + MFPR_PULL_HIGH, + MFPR_PULL_BOTH, +}; + +/* mapping of MFP_LPM_EDGE_* definitions to MFPR_EDGE_* register bits */ - const static unsigned long mfpr_edge[] = { ++static const unsigned long mfpr_edge[] = { + MFPR_EDGE_NONE, + MFPR_EDGE_RISE, + MFPR_EDGE_FALL, + MFPR_EDGE_BOTH, +}; + +#define mfpr_readl(off) \ + __raw_readl(mfpr_mmio_base + (off)) + +#define mfpr_writel(off, val) \ + __raw_writel(val, mfpr_mmio_base + (off)) + +#define mfp_configured(p) ((p)->config != -1) + +/* + * perform a read-back of any MFPR register to make sure the + * previous writings are finished + */ +#define mfpr_sync() (void)__raw_readl(mfpr_mmio_base + 0) + +static inline void __mfp_config_run(struct pxa3xx_mfp_pin *p) +{ + if (mfp_configured(p)) + mfpr_writel(p->mfpr_off, p->mfpr_run); +} + +static inline void __mfp_config_lpm(struct pxa3xx_mfp_pin *p) +{ + if (mfp_configured(p)) { + unsigned long mfpr_clr = (p->mfpr_run & ~MFPR_EDGE_BOTH) | MFPR_EDGE_CLEAR; + if (mfpr_clr != p->mfpr_run) + mfpr_writel(p->mfpr_off, mfpr_clr); + if (p->mfpr_lpm != mfpr_clr) + mfpr_writel(p->mfpr_off, p->mfpr_lpm); + } +} + +void pxa3xx_mfp_config(unsigned long *mfp_cfgs, int num) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&mfp_spin_lock, flags); + + for (i = 0; i < num; i++, mfp_cfgs++) { + unsigned long tmp, c = *mfp_cfgs; + struct pxa3xx_mfp_pin *p; + int pin, af, drv, lpm, edge, pull; + + pin = MFP_PIN(c); + BUG_ON(pin >= MFP_PIN_MAX); + p = &mfp_table[pin]; + + af = MFP_AF(c); + drv = MFP_DS(c); + lpm = MFP_LPM_STATE(c); + edge = MFP_LPM_EDGE(c); + pull = MFP_PULL(c); + + /* run-mode pull settings will conflict with MFPR bits of + * low power mode state, calculate mfpr_run and mfpr_lpm + * individually if pull != MFP_PULL_NONE + */ + tmp = MFPR_AF_SEL(af) | MFPR_DRIVE(drv); + + if (likely(pull == MFP_PULL_NONE)) { + p->mfpr_run = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; + p->mfpr_lpm = p->mfpr_run; + } else { + p->mfpr_lpm = tmp | mfpr_lpm[lpm] | mfpr_edge[edge]; + p->mfpr_run = tmp | mfpr_pull[pull]; + } + + p->config = c; __mfp_config_run(p); + } + + mfpr_sync(); + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +unsigned long pxa3xx_mfp_read(int mfp) +{ + unsigned long val, flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + val = mfpr_readl(mfp_table[mfp].mfpr_off); + spin_unlock_irqrestore(&mfp_spin_lock, flags); + + return val; +} + +void pxa3xx_mfp_write(int mfp, unsigned long val) +{ + unsigned long flags; + + BUG_ON(mfp >= MFP_PIN_MAX); + + spin_lock_irqsave(&mfp_spin_lock, flags); + mfpr_writel(mfp_table[mfp].mfpr_off, val); + mfpr_sync(); + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void __init pxa3xx_mfp_init_addr(struct pxa3xx_mfp_addr_map *map) +{ + struct pxa3xx_mfp_addr_map *p; + unsigned long offset, flags; + int i; + + spin_lock_irqsave(&mfp_spin_lock, flags); + + for (p = map; p->start != MFP_PIN_INVALID; p++) { + offset = p->offset; + i = p->start; + + do { + mfp_table[i].mfpr_off = offset; + mfp_table[i].mfpr_run = 0; + mfp_table[i].mfpr_lpm = 0; + offset += 4; i++; + } while ((i <= p->end) && (p->end != -1)); + } + + spin_unlock_irqrestore(&mfp_spin_lock, flags); +} + +void __init pxa3xx_init_mfp(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mfp_table); i++) + mfp_table[i].config = -1; +} + +#ifdef CONFIG_PM +/* + * Configure the MFPs appropriately for suspend/resume. + * FIXME: this should probably depend on which system state we're + * entering - for instance, we might not want to place MFP pins in + * a pull-down mode if they're an active low chip select, and we're + * just entering standby. + */ +static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state) +{ + int pin; + + for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { + struct pxa3xx_mfp_pin *p = &mfp_table[pin]; + __mfp_config_lpm(p); + } + return 0; +} + +static int pxa3xx_mfp_resume(struct sys_device *d) +{ + int pin; + + for (pin = 0; pin < ARRAY_SIZE(mfp_table); pin++) { + struct pxa3xx_mfp_pin *p = &mfp_table[pin]; + __mfp_config_run(p); + } + + /* clear RDH bit when MFP settings are restored + * + * NOTE: the last 3 bits DxS are write-1-to-clear so carefully + * preserve them here in case they will be referenced later + */ + ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S); + + return 0; +} +#else +#define pxa3xx_mfp_suspend NULL +#define pxa3xx_mfp_resume NULL +#endif + +struct sysdev_class pxa3xx_mfp_sysclass = { + .name = "mfp", + .suspend = pxa3xx_mfp_suspend, + .resume = pxa3xx_mfp_resume, +}; + +static int __init mfp_init_devicefs(void) +{ + if (cpu_is_pxa3xx()) + return sysdev_class_register(&pxa3xx_mfp_sysclass); + + return 0; +} +postcore_initcall(mfp_init_devicefs); diff --cc samples/firmware_class/firmware_sample_driver.c index 165cff98032e,000000000000..11114f389c49 mode 100644,000000..100644 --- a/samples/firmware_class/firmware_sample_driver.c +++ b/samples/firmware_class/firmware_sample_driver.c @@@ -1,120 -1,0 +1,121 @@@ +/* + * firmware_sample_driver.c - + * + * Copyright (c) 2003 Manuel Estrada Sainz + * + * Sample code on how to use request_firmware() from drivers. + * + */ + +#include +#include +#include +#include +#include +#include + +static struct device ghost_device = { + .bus_id = "ghost0", +}; + + +static void sample_firmware_load(char *firmware, int size) +{ + u8 buf[size+1]; + memcpy(buf, firmware, size); + buf[size] = '\0'; + printk(KERN_INFO "firmware_sample_driver: firmware: %s\n", buf); +} + +static void sample_probe_default(void) +{ + /* uses the default method to get the firmware */ + const struct firmware *fw_entry; + int retval; + + printk(KERN_INFO "firmware_sample_driver: " + "a ghost device got inserted :)\n"); + + retval = request_firmware(&fw_entry, "sample_driver_fw", &ghost_device); + if (retval) { + printk(KERN_ERR + "firmware_sample_driver: Firmware not available\n"); + return; + } + + sample_firmware_load(fw_entry->data, fw_entry->size); + + release_firmware(fw_entry); + + /* finish setting up the device */ +} + +static void sample_probe_specific(void) +{ + int retval; + /* Uses some specific hotplug support to get the firmware from + * userspace directly into the hardware, or via some sysfs file */ + + /* NOTE: This currently doesn't work */ + + printk(KERN_INFO "firmware_sample_driver: " + "a ghost device got inserted :)\n"); + + retval = request_firmware(NULL, "sample_driver_fw", &ghost_device); + if (retval) { + printk(KERN_ERR + "firmware_sample_driver: Firmware load failed\n"); + return; + } + + /* request_firmware blocks until userspace finished, so at + * this point the firmware should be already in the device */ + + /* finish setting up the device */ +} ++ +static void sample_probe_async_cont(const struct firmware *fw, void *context) +{ + if (!fw) { + printk(KERN_ERR + "firmware_sample_driver: firmware load failed\n"); + return; + } + + printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n", + (char *)context); + sample_firmware_load(fw->data, fw->size); +} + +static void sample_probe_async(void) +{ + /* Let's say that I can't sleep */ + int error; + error = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, + "sample_driver_fw", &ghost_device, + "my device pointer", + sample_probe_async_cont); + if (error) + printk(KERN_ERR "firmware_sample_driver:" + " request_firmware_nowait failed\n"); +} + +static int sample_init(void) +{ + device_initialize(&ghost_device); + /* since there is no real hardware insertion I just call the + * sample probe functions here */ + sample_probe_specific(); + sample_probe_default(); + sample_probe_async(); + return 0; +} + +static void __exit sample_exit(void) +{ +} + +module_init(sample_init); +module_exit(sample_exit); + +MODULE_LICENSE("GPL");