diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 33 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/atmel_tclib.c | 161 | ||||
-rw-r--r-- | drivers/misc/enclosure.c | 118 |
4 files changed, 259 insertions, 54 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 962817e49fb..bb94ce78a6d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -22,6 +22,39 @@ config ATMEL_PWM purposes including software controlled power-efficent backlights on LCD displays, motor control, and waveform generation. +config ATMEL_TCLIB + bool "Atmel AT32/AT91 Timer/Counter Library" + depends on (AVR32 || ARCH_AT91) + help + Select this if you want a library to allocate the Timer/Counter + blocks found on many Atmel processors. This facilitates using + these blocks by different drivers despite processor differences. + +config ATMEL_TCB_CLKSRC + bool "TC Block Clocksource" + depends on ATMEL_TCLIB && GENERIC_TIME + default y + help + Select this to get a high precision clocksource based on a + TC block with a 5+ MHz base clock rate. Two timer channels + are combined to make a single 32-bit timer. + + When GENERIC_CLOCKEVENTS is defined, the third timer channel + may be used as a clock event device supporting oneshot mode + (delays of up to two seconds) based on the 32 KiHz clock. + +config ATMEL_TCB_CLKSRC_BLOCK + int + depends on ATMEL_TCB_CLKSRC + prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X + default 0 + range 0 1 + help + Some chips provide more than one TC block, so you have the + choice of which one to use for the clock framework. The other + TC can be used for other purposes, such as PWM generation and + interval timing. + config IBM_ASM tristate "Device driver for IBM RSA service processor" depends on X86 && PCI && INPUT && EXPERIMENTAL diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index bbc69fdd1b9..4581b253311 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o +obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c new file mode 100644 index 00000000000..05dc8a31f28 --- /dev/null +++ b/drivers/misc/atmel_tclib.c @@ -0,0 +1,161 @@ +#include <linux/atmel_tc.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +/* Number of bytes to reserve for the iomem resource */ +#define ATMEL_TC_IOMEM_SIZE 256 + + +/* + * This is a thin library to solve the problem of how to portably allocate + * one of the TC blocks. For simplicity, it doesn't currently expect to + * share individual timers between different drivers. + */ + +#if defined(CONFIG_AVR32) +/* AVR32 has these divide PBB */ +const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, }; +EXPORT_SYMBOL(atmel_tc_divisors); + +#elif defined(CONFIG_ARCH_AT91) +/* AT91 has these divide MCK */ +const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, }; +EXPORT_SYMBOL(atmel_tc_divisors); + +#endif + +static DEFINE_SPINLOCK(tc_list_lock); +static LIST_HEAD(tc_list); + +/** + * atmel_tc_alloc - allocate a specified TC block + * @block: which block to allocate + * @name: name to be associated with the iomem resource + * + * Caller allocates a block. If it is available, a pointer to a + * pre-initialized struct atmel_tc is returned. The caller can access + * the registers directly through the "regs" field. + */ +struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) +{ + struct atmel_tc *tc; + struct platform_device *pdev = NULL; + struct resource *r; + + spin_lock(&tc_list_lock); + list_for_each_entry(tc, &tc_list, node) { + if (tc->pdev->id == block) { + pdev = tc->pdev; + break; + } + } + + if (!pdev || tc->iomem) + goto fail; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name); + if (!r) + goto fail; + + tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE); + if (!tc->regs) + goto fail_ioremap; + + tc->iomem = r; + +out: + spin_unlock(&tc_list_lock); + return tc; + +fail_ioremap: + release_resource(r); +fail: + tc = NULL; + goto out; +} +EXPORT_SYMBOL_GPL(atmel_tc_alloc); + +/** + * atmel_tc_free - release a specified TC block + * @tc: Timer/counter block that was returned by atmel_tc_alloc() + * + * This reverses the effect of atmel_tc_alloc(), unmapping the I/O + * registers, invalidating the resource returned by that routine and + * making the TC available to other drivers. + */ +void atmel_tc_free(struct atmel_tc *tc) +{ + spin_lock(&tc_list_lock); + if (tc->regs) { + iounmap(tc->regs); + release_resource(tc->iomem); + tc->regs = NULL; + tc->iomem = NULL; + } + spin_unlock(&tc_list_lock); +} +EXPORT_SYMBOL_GPL(atmel_tc_free); + +static int __init tc_probe(struct platform_device *pdev) +{ + struct atmel_tc *tc; + struct clk *clk; + int irq; + + if (!platform_get_resource(pdev, IORESOURCE_MEM, 0)) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL); + if (!tc) + return -ENOMEM; + + tc->pdev = pdev; + + clk = clk_get(&pdev->dev, "t0_clk"); + if (IS_ERR(clk)) { + kfree(tc); + return -EINVAL; + } + + tc->clk[0] = clk; + tc->clk[1] = clk_get(&pdev->dev, "t1_clk"); + if (IS_ERR(tc->clk[1])) + tc->clk[1] = clk; + tc->clk[2] = clk_get(&pdev->dev, "t2_clk"); + if (IS_ERR(tc->clk[2])) + tc->clk[2] = clk; + + tc->irq[0] = irq; + tc->irq[1] = platform_get_irq(pdev, 1); + if (tc->irq[1] < 0) + tc->irq[1] = irq; + tc->irq[2] = platform_get_irq(pdev, 2); + if (tc->irq[2] < 0) + tc->irq[2] = irq; + + spin_lock(&tc_list_lock); + list_add_tail(&tc->node, &tc_list); + spin_unlock(&tc_list_lock); + + return 0; +} + +static struct platform_driver tc_driver = { + .driver.name = "atmel_tcb", +}; + +static int __init tc_init(void) +{ + return platform_driver_probe(&tc_driver, tc_probe); +} +arch_initcall(tc_init); diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 6fcb0e96adf..fafb57fed76 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -40,16 +40,16 @@ static struct class enclosure_component_class; * Looks through the list of registered enclosures to see * if it can find a match for a device. Returns NULL if no * enclosure is found. Obtains a reference to the enclosure class - * device which must be released with class_device_put(). + * device which must be released with device_put(). */ struct enclosure_device *enclosure_find(struct device *dev) { - struct enclosure_device *edev = NULL; + struct enclosure_device *edev; mutex_lock(&container_list_lock); list_for_each_entry(edev, &container_list, node) { - if (edev->cdev.dev == dev) { - class_device_get(&edev->cdev); + if (edev->edev.parent == dev) { + get_device(&edev->edev); mutex_unlock(&container_list_lock); return edev; } @@ -117,11 +117,11 @@ enclosure_register(struct device *dev, const char *name, int components, edev->components = components; - edev->cdev.class = &enclosure_class; - edev->cdev.dev = get_device(dev); + edev->edev.class = &enclosure_class; + edev->edev.parent = get_device(dev); edev->cb = cb; - snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name); - err = class_device_register(&edev->cdev); + snprintf(edev->edev.bus_id, BUS_ID_SIZE, "%s", name); + err = device_register(&edev->edev); if (err) goto err; @@ -135,7 +135,7 @@ enclosure_register(struct device *dev, const char *name, int components, return edev; err: - put_device(edev->cdev.dev); + put_device(edev->edev.parent); kfree(edev); return ERR_PTR(err); } @@ -158,27 +158,28 @@ void enclosure_unregister(struct enclosure_device *edev) for (i = 0; i < edev->components; i++) if (edev->component[i].number != -1) - class_device_unregister(&edev->component[i].cdev); + device_unregister(&edev->component[i].cdev); /* prevent any callbacks into service user */ edev->cb = &enclosure_null_callbacks; - class_device_unregister(&edev->cdev); + device_unregister(&edev->edev); } EXPORT_SYMBOL_GPL(enclosure_unregister); -static void enclosure_release(struct class_device *cdev) +static void enclosure_release(struct device *cdev) { struct enclosure_device *edev = to_enclosure_device(cdev); - put_device(cdev->dev); + put_device(cdev->parent); kfree(edev); } -static void enclosure_component_release(struct class_device *cdev) +static void enclosure_component_release(struct device *dev) { - if (cdev->dev) - put_device(cdev->dev); - class_device_put(cdev->parent); + struct enclosure_component *cdev = to_enclosure_component(dev); + + put_device(cdev->dev); + put_device(dev->parent); } /** @@ -201,7 +202,7 @@ enclosure_component_register(struct enclosure_device *edev, const char *name) { struct enclosure_component *ecomp; - struct class_device *cdev; + struct device *cdev; int err; if (number >= edev->components) @@ -215,14 +216,14 @@ enclosure_component_register(struct enclosure_device *edev, ecomp->type = type; ecomp->number = number; cdev = &ecomp->cdev; - cdev->parent = class_device_get(&edev->cdev); + cdev->parent = get_device(&edev->edev); cdev->class = &enclosure_component_class; if (name) - snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name); + snprintf(cdev->bus_id, BUS_ID_SIZE, "%s", name); else - snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number); + snprintf(cdev->bus_id, BUS_ID_SIZE, "%u", number); - err = class_device_register(cdev); + err = device_register(cdev); if (err) ERR_PTR(err); @@ -247,18 +248,17 @@ EXPORT_SYMBOL_GPL(enclosure_component_register); int enclosure_add_device(struct enclosure_device *edev, int component, struct device *dev) { - struct class_device *cdev; + struct enclosure_component *cdev; if (!edev || component >= edev->components) return -EINVAL; - cdev = &edev->component[component].cdev; + cdev = &edev->component[component]; - class_device_del(cdev); - if (cdev->dev) - put_device(cdev->dev); + device_del(&cdev->cdev); + put_device(cdev->dev); cdev->dev = get_device(dev); - return class_device_add(cdev); + return device_add(&cdev->cdev); } EXPORT_SYMBOL_GPL(enclosure_add_device); @@ -272,18 +272,17 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); */ int enclosure_remove_device(struct enclosure_device *edev, int component) { - struct class_device *cdev; + struct enclosure_component *cdev; if (!edev || component >= edev->components) return -EINVAL; - cdev = &edev->component[component].cdev; + cdev = &edev->component[component]; - class_device_del(cdev); - if (cdev->dev) - put_device(cdev->dev); + device_del(&cdev->cdev); + put_device(cdev->dev); cdev->dev = NULL; - return class_device_add(cdev); + return device_add(&cdev->cdev); } EXPORT_SYMBOL_GPL(enclosure_remove_device); @@ -291,14 +290,16 @@ EXPORT_SYMBOL_GPL(enclosure_remove_device); * sysfs pieces below */ -static ssize_t enclosure_show_components(struct class_device *cdev, char *buf) +static ssize_t enclosure_show_components(struct device *cdev, + struct device_attribute *attr, + char *buf) { struct enclosure_device *edev = to_enclosure_device(cdev); return snprintf(buf, 40, "%d\n", edev->components); } -static struct class_device_attribute enclosure_attrs[] = { +static struct device_attribute enclosure_attrs[] = { __ATTR(components, S_IRUGO, enclosure_show_components, NULL), __ATTR_NULL }; @@ -306,8 +307,8 @@ static struct class_device_attribute enclosure_attrs[] = { static struct class enclosure_class = { .name = "enclosure", .owner = THIS_MODULE, - .release = enclosure_release, - .class_dev_attrs = enclosure_attrs, + .dev_release = enclosure_release, + .dev_attrs = enclosure_attrs, }; static const char *const enclosure_status [] = { @@ -326,7 +327,8 @@ static const char *const enclosure_type [] = { [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device", }; -static ssize_t get_component_fault(struct class_device *cdev, char *buf) +static ssize_t get_component_fault(struct device *cdev, + struct device_attribute *attr, char *buf) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -336,8 +338,9 @@ static ssize_t get_component_fault(struct class_device *cdev, char *buf) return snprintf(buf, 40, "%d\n", ecomp->fault); } -static ssize_t set_component_fault(struct class_device *cdev, const char *buf, - size_t count) +static ssize_t set_component_fault(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -348,7 +351,8 @@ static ssize_t set_component_fault(struct class_device *cdev, const char *buf, return count; } -static ssize_t get_component_status(struct class_device *cdev, char *buf) +static ssize_t get_component_status(struct device *cdev, + struct device_attribute *attr,char *buf) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -358,8 +362,9 @@ static ssize_t get_component_status(struct class_device *cdev, char *buf) return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]); } -static ssize_t set_component_status(struct class_device *cdev, const char *buf, - size_t count) +static ssize_t set_component_status(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -380,7 +385,8 @@ static ssize_t set_component_status(struct class_device *cdev, const char *buf, return -EINVAL; } -static ssize_t get_component_active(struct class_device *cdev, char *buf) +static ssize_t get_component_active(struct device *cdev, + struct device_attribute *attr, char *buf) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -390,8 +396,9 @@ static ssize_t get_component_active(struct class_device *cdev, char *buf) return snprintf(buf, 40, "%d\n", ecomp->active); } -static ssize_t set_component_active(struct class_device *cdev, const char *buf, - size_t count) +static ssize_t set_component_active(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -402,7 +409,8 @@ static ssize_t set_component_active(struct class_device *cdev, const char *buf, return count; } -static ssize_t get_component_locate(struct class_device *cdev, char *buf) +static ssize_t get_component_locate(struct device *cdev, + struct device_attribute *attr, char *buf) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -412,8 +420,9 @@ static ssize_t get_component_locate(struct class_device *cdev, char *buf) return snprintf(buf, 40, "%d\n", ecomp->locate); } -static ssize_t set_component_locate(struct class_device *cdev, const char *buf, - size_t count) +static ssize_t set_component_locate(struct device *cdev, + struct device_attribute *attr, + const char *buf, size_t count) { struct enclosure_device *edev = to_enclosure_device(cdev->parent); struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -424,7 +433,8 @@ static ssize_t set_component_locate(struct class_device *cdev, const char *buf, return count; } -static ssize_t get_component_type(struct class_device *cdev, char *buf) +static ssize_t get_component_type(struct device *cdev, + struct device_attribute *attr, char *buf) { struct enclosure_component *ecomp = to_enclosure_component(cdev); @@ -432,7 +442,7 @@ static ssize_t get_component_type(struct class_device *cdev, char *buf) } -static struct class_device_attribute enclosure_component_attrs[] = { +static struct device_attribute enclosure_component_attrs[] = { __ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault, set_component_fault), __ATTR(status, S_IRUGO | S_IWUSR, get_component_status, @@ -448,8 +458,8 @@ static struct class_device_attribute enclosure_component_attrs[] = { static struct class enclosure_component_class = { .name = "enclosure_component", .owner = THIS_MODULE, - .class_dev_attrs = enclosure_component_attrs, - .release = enclosure_component_release, + .dev_attrs = enclosure_component_attrs, + .dev_release = enclosure_component_release, }; static int __init enclosure_init(void) |