11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for PC-speaker like devices found on various Sparc systems. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2002 Vojtech Pavlik 59c1a5077fdca99356c891af37931e537dea874f5David S. Miller * Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net) 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 119c1a5077fdca99356c891af37931e537dea874f5David S. Miller#include <linux/of_device.h> 125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16a2bd4fd17926d715a470fbe0ebe05128ba410984David S. MillerMODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 1776b7cddfd576331761e945a508254abad11039e9Dmitry TorokhovMODULE_DESCRIPTION("Sparc Speaker beeper driver"); 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 209c1a5077fdca99356c891af37931e537dea874f5David S. Millerstruct grover_beep_info { 219c1a5077fdca99356c891af37931e537dea874f5David S. Miller void __iomem *freq_regs; 229c1a5077fdca99356c891af37931e537dea874f5David S. Miller void __iomem *enable_reg; 239c1a5077fdca99356c891af37931e537dea874f5David S. Miller}; 249c1a5077fdca99356c891af37931e537dea874f5David S. Miller 259c1a5077fdca99356c891af37931e537dea874f5David S. Millerstruct bbc_beep_info { 269c1a5077fdca99356c891af37931e537dea874f5David S. Miller u32 clock_freq; 279c1a5077fdca99356c891af37931e537dea874f5David S. Miller void __iomem *regs; 289c1a5077fdca99356c891af37931e537dea874f5David S. Miller}; 299c1a5077fdca99356c891af37931e537dea874f5David S. Miller 30a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Millerstruct sparcspkr_state { 31a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller const char *name; 32a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); 33a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller spinlock_t lock; 34a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller struct input_dev *input_dev; 359c1a5077fdca99356c891af37931e537dea874f5David S. Miller union { 369c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct grover_beep_info grover; 379c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct bbc_beep_info bbc; 389c1a5077fdca99356c891af37931e537dea874f5David S. Miller } u; 39a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller}; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 419c1a5077fdca99356c891af37931e537dea874f5David S. Millerstatic u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count) 429c1a5077fdca99356c891af37931e537dea874f5David S. Miller{ 439c1a5077fdca99356c891af37931e537dea874f5David S. Miller u32 val, clock_freq = info->clock_freq; 449c1a5077fdca99356c891af37931e537dea874f5David S. Miller int i; 459c1a5077fdca99356c891af37931e537dea874f5David S. Miller 469c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!count) 479c1a5077fdca99356c891af37931e537dea874f5David S. Miller return 0; 489c1a5077fdca99356c891af37931e537dea874f5David S. Miller 499c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (count <= clock_freq >> 20) 509c1a5077fdca99356c891af37931e537dea874f5David S. Miller return 1 << 18; 519c1a5077fdca99356c891af37931e537dea874f5David S. Miller 529c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (count >= clock_freq >> 12) 539c1a5077fdca99356c891af37931e537dea874f5David S. Miller return 1 << 10; 549c1a5077fdca99356c891af37931e537dea874f5David S. Miller 559c1a5077fdca99356c891af37931e537dea874f5David S. Miller val = 1 << 18; 569c1a5077fdca99356c891af37931e537dea874f5David S. Miller for (i = 19; i >= 11; i--) { 579c1a5077fdca99356c891af37931e537dea874f5David S. Miller val >>= 1; 589c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (count <= clock_freq >> i) 599c1a5077fdca99356c891af37931e537dea874f5David S. Miller break; 609c1a5077fdca99356c891af37931e537dea874f5David S. Miller } 619c1a5077fdca99356c891af37931e537dea874f5David S. Miller 629c1a5077fdca99356c891af37931e537dea874f5David S. Miller return val; 639c1a5077fdca99356c891af37931e537dea874f5David S. Miller} 649c1a5077fdca99356c891af37931e537dea874f5David S. Miller 659c1a5077fdca99356c891af37931e537dea874f5David S. Millerstatic int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 67293e6392d72dfaef1f6aef605769869512bec45dDmitry Torokhov struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); 689c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct bbc_beep_info *info = &state->u.bbc; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count = 0; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type != EV_SND) 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (code) { 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SND_BELL: if (value) value = 1000; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SND_TONE: break; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -1; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value > 20 && value < 32767) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = 1193182 / value; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 849c1a5077fdca99356c891af37931e537dea874f5David S. Miller count = bbc_count_to_reg(info, count); 859c1a5077fdca99356c891af37931e537dea874f5David S. Miller 86a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller spin_lock_irqsave(&state->lock, flags); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 889c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (count) { 899c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(0x01, info->regs + 0); 909c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(0x00, info->regs + 2); 919c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb((count >> 16) & 0xff, info->regs + 3); 929c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb((count >> 8) & 0xff, info->regs + 4); 939c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(0x00, info->regs + 5); 949c1a5077fdca99356c891af37931e537dea874f5David S. Miller } else { 959c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(0x00, info->regs + 0); 969c1a5077fdca99356c891af37931e537dea874f5David S. Miller } 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 98a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller spin_unlock_irqrestore(&state->lock, flags); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1039c1a5077fdca99356c891af37931e537dea874f5David S. Millerstatic int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 105293e6392d72dfaef1f6aef605769869512bec45dDmitry Torokhov struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); 1069c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct grover_beep_info *info = &state->u.grover; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count = 0; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type != EV_SND) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (code) { 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SND_BELL: if (value) value = 1000; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SND_TONE: break; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: return -1; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value > 20 && value < 32767) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = 1193182 / value; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 122a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller spin_lock_irqsave(&state->lock, flags); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count) { 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable counter 2 */ 1269c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(inb(info->enable_reg) | 3, info->enable_reg); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set command for counter 2, 2 byte write */ 1289c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(0xB6, info->freq_regs + 1); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* select desired HZ */ 1309c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(count & 0xff, info->freq_regs + 0); 1319c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb((count >> 8) & 0xff, info->freq_regs + 0); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable counter 2 */ 1349c1a5077fdca99356c891af37931e537dea874f5David S. Miller outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 137a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller spin_unlock_irqrestore(&state->lock, flags); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 142a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Millerstatic int __devinit sparcspkr_probe(struct device *dev) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 144a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller struct sparcspkr_state *state = dev_get_drvdata(dev); 145f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov struct input_dev *input_dev; 146f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov int error; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_dev = input_allocate_device(); 149f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov if (!input_dev) 15076b7cddfd576331761e945a508254abad11039e9Dmitry Torokhov return -ENOMEM; 15176b7cddfd576331761e945a508254abad11039e9Dmitry Torokhov 152a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller input_dev->name = state->name; 153f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_dev->phys = "sparc/input0"; 154f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_dev->id.bustype = BUS_ISA; 155f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_dev->id.vendor = 0x001f; 156f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_dev->id.product = 0x0001; 157f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_dev->id.version = 0x0100; 158293e6392d72dfaef1f6aef605769869512bec45dDmitry Torokhov input_dev->dev.parent = dev; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1607b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_SND); 1617b19ada2ed3c1eccb9fe94d74b05e1428224663dJiri Slaby input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 163a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller input_dev->event = state->event; 164f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 165f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov error = input_register_device(input_dev); 166f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov if (error) { 167f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov input_free_device(input_dev); 168f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov return error; 169f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov } 170f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 171a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller state->input_dev = input_dev; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 175f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 1764ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic void sparcspkr_shutdown(struct platform_device *dev) 177f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov{ 178a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller struct sparcspkr_state *state = dev_get_drvdata(&dev->dev); 179a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller struct input_dev *input_dev = state->input_dev; 180f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 181f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov /* turn off the speaker */ 182a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller state->event(input_dev, EV_SND, SND_BELL, 0); 183f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov} 184f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 1854ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic int __devinit bbc_beep_probe(struct platform_device *op) 186f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov{ 1879c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct sparcspkr_state *state; 1889c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct bbc_beep_info *info; 1899c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct device_node *dp; 1909c1a5077fdca99356c891af37931e537dea874f5David S. Miller int err = -ENOMEM; 191a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 1929c1a5077fdca99356c891af37931e537dea874f5David S. Miller state = kzalloc(sizeof(*state), GFP_KERNEL); 1939c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!state) 1949c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_err; 1959c1a5077fdca99356c891af37931e537dea874f5David S. Miller 1969c1a5077fdca99356c891af37931e537dea874f5David S. Miller state->name = "Sparc BBC Speaker"; 1979c1a5077fdca99356c891af37931e537dea874f5David S. Miller state->event = bbc_spkr_event; 1989c1a5077fdca99356c891af37931e537dea874f5David S. Miller spin_lock_init(&state->lock); 1999c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2009c1a5077fdca99356c891af37931e537dea874f5David S. Miller dp = of_find_node_by_path("/"); 2019c1a5077fdca99356c891af37931e537dea874f5David S. Miller err = -ENODEV; 2029c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!dp) 2039c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_free; 2049c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2059c1a5077fdca99356c891af37931e537dea874f5David S. Miller info = &state->u.bbc; 2069c1a5077fdca99356c891af37931e537dea874f5David S. Miller info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0); 2079c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!info->clock_freq) 2089c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_free; 2099c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2109c1a5077fdca99356c891af37931e537dea874f5David S. Miller info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep"); 2119c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!info->regs) 2129c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_free; 2139c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2149c1a5077fdca99356c891af37931e537dea874f5David S. Miller dev_set_drvdata(&op->dev, state); 2159c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2169c1a5077fdca99356c891af37931e537dea874f5David S. Miller err = sparcspkr_probe(&op->dev); 2179c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (err) 2189c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_clear_drvdata; 219a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 220a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller return 0; 2219c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2229c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_clear_drvdata: 2239c1a5077fdca99356c891af37931e537dea874f5David S. Miller dev_set_drvdata(&op->dev, NULL); 2249c1a5077fdca99356c891af37931e537dea874f5David S. Miller of_iounmap(&op->resource[0], info->regs, 6); 2259c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2269c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_free: 2279c1a5077fdca99356c891af37931e537dea874f5David S. Miller kfree(state); 2289c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_err: 2299c1a5077fdca99356c891af37931e537dea874f5David S. Miller return err; 230a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller} 231a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 2322dc11581376829303b98eadb2de253bee065a56aGrant Likelystatic int __devexit bbc_remove(struct platform_device *op) 233a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller{ 2349c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct sparcspkr_state *state = dev_get_drvdata(&op->dev); 2359c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct input_dev *input_dev = state->input_dev; 2369c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct bbc_beep_info *info = &state->u.bbc; 237a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 2389c1a5077fdca99356c891af37931e537dea874f5David S. Miller /* turn off the speaker */ 2399c1a5077fdca99356c891af37931e537dea874f5David S. Miller state->event(input_dev, EV_SND, SND_BELL, 0); 240a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 2419c1a5077fdca99356c891af37931e537dea874f5David S. Miller input_unregister_device(input_dev); 242a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 2439c1a5077fdca99356c891af37931e537dea874f5David S. Miller of_iounmap(&op->resource[0], info->regs, 6); 244a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 2459c1a5077fdca99356c891af37931e537dea874f5David S. Miller dev_set_drvdata(&op->dev, NULL); 2469c1a5077fdca99356c891af37931e537dea874f5David S. Miller kfree(state); 247a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 248a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller return 0; 249f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov} 250f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 251fd098316ef533e8441576f020ead4beab93154ceDavid S. Millerstatic const struct of_device_id bbc_beep_match[] = { 252a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller { 253a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller .name = "beep", 2549c1a5077fdca99356c891af37931e537dea874f5David S. Miller .compatible = "SUNW,bbc-beep", 255f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov }, 256a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller {}, 257f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov}; 258f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 2594ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic struct platform_driver bbc_beep_driver = { 2604018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .driver = { 2614018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .name = "bbcbeep", 2624018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .owner = THIS_MODULE, 2634018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .of_match_table = bbc_beep_match, 2644018294b53d1dae026880e45f174c1cc63b5d435Grant Likely }, 2659c1a5077fdca99356c891af37931e537dea874f5David S. Miller .probe = bbc_beep_probe, 2669c1a5077fdca99356c891af37931e537dea874f5David S. Miller .remove = __devexit_p(bbc_remove), 267a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller .shutdown = sparcspkr_shutdown, 268a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller}; 269f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 2704ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic int __devinit grover_beep_probe(struct platform_device *op) 271f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov{ 272a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller struct sparcspkr_state *state; 2739c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct grover_beep_info *info; 2749c1a5077fdca99356c891af37931e537dea874f5David S. Miller int err = -ENOMEM; 275f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 276a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller state = kzalloc(sizeof(*state), GFP_KERNEL); 277a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller if (!state) 2789c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_err; 279f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 2809c1a5077fdca99356c891af37931e537dea874f5David S. Miller state->name = "Sparc Grover Speaker"; 2819c1a5077fdca99356c891af37931e537dea874f5David S. Miller state->event = grover_spkr_event; 282a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller spin_lock_init(&state->lock); 283a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 2849c1a5077fdca99356c891af37931e537dea874f5David S. Miller info = &state->u.grover; 2859c1a5077fdca99356c891af37931e537dea874f5David S. Miller info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq"); 2869c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!info->freq_regs) 2879c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_free; 288f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 2899c1a5077fdca99356c891af37931e537dea874f5David S. Miller info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable"); 2909c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (!info->enable_reg) 2919c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_unmap_freq_regs; 2929c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2939c1a5077fdca99356c891af37931e537dea874f5David S. Miller dev_set_drvdata(&op->dev, state); 2949c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2959c1a5077fdca99356c891af37931e537dea874f5David S. Miller err = sparcspkr_probe(&op->dev); 2969c1a5077fdca99356c891af37931e537dea874f5David S. Miller if (err) 2979c1a5077fdca99356c891af37931e537dea874f5David S. Miller goto out_clear_drvdata; 2989c1a5077fdca99356c891af37931e537dea874f5David S. Miller 2999c1a5077fdca99356c891af37931e537dea874f5David S. Miller return 0; 3009c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3019c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_clear_drvdata: 3029c1a5077fdca99356c891af37931e537dea874f5David S. Miller dev_set_drvdata(&op->dev, NULL); 3039c1a5077fdca99356c891af37931e537dea874f5David S. Miller of_iounmap(&op->resource[3], info->enable_reg, 1); 3049c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3059c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_unmap_freq_regs: 3069c1a5077fdca99356c891af37931e537dea874f5David S. Miller of_iounmap(&op->resource[2], info->freq_regs, 2); 3079c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_free: 3089c1a5077fdca99356c891af37931e537dea874f5David S. Miller kfree(state); 3099c1a5077fdca99356c891af37931e537dea874f5David S. Millerout_err: 3109c1a5077fdca99356c891af37931e537dea874f5David S. Miller return err; 3119c1a5077fdca99356c891af37931e537dea874f5David S. Miller} 3129c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3132dc11581376829303b98eadb2de253bee065a56aGrant Likelystatic int __devexit grover_remove(struct platform_device *op) 3149c1a5077fdca99356c891af37931e537dea874f5David S. Miller{ 3159c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct sparcspkr_state *state = dev_get_drvdata(&op->dev); 3169c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct grover_beep_info *info = &state->u.grover; 3179c1a5077fdca99356c891af37931e537dea874f5David S. Miller struct input_dev *input_dev = state->input_dev; 3189c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3199c1a5077fdca99356c891af37931e537dea874f5David S. Miller /* turn off the speaker */ 3209c1a5077fdca99356c891af37931e537dea874f5David S. Miller state->event(input_dev, EV_SND, SND_BELL, 0); 3219c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3229c1a5077fdca99356c891af37931e537dea874f5David S. Miller input_unregister_device(input_dev); 3239c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3249c1a5077fdca99356c891af37931e537dea874f5David S. Miller of_iounmap(&op->resource[3], info->enable_reg, 1); 3259c1a5077fdca99356c891af37931e537dea874f5David S. Miller of_iounmap(&op->resource[2], info->freq_regs, 2); 3269c1a5077fdca99356c891af37931e537dea874f5David S. Miller 3279c1a5077fdca99356c891af37931e537dea874f5David S. Miller dev_set_drvdata(&op->dev, NULL); 3289c1a5077fdca99356c891af37931e537dea874f5David S. Miller kfree(state); 329f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 330f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov return 0; 331a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller} 332f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 333fd098316ef533e8441576f020ead4beab93154ceDavid S. Millerstatic const struct of_device_id grover_beep_match[] = { 334a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller { 3359c1a5077fdca99356c891af37931e537dea874f5David S. Miller .name = "beep", 3369c1a5077fdca99356c891af37931e537dea874f5David S. Miller .compatible = "SUNW,smbus-beep", 337a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller }, 338a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller {}, 339a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller}; 340f5b64078d75528f36b78d30e945bb1b05cb05f26Dmitry Torokhov 3414ebb24f707187196937607c60810d42f7112d7aaGrant Likelystatic struct platform_driver grover_beep_driver = { 3424018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .driver = { 3434018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .name = "groverbeep", 3444018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .owner = THIS_MODULE, 3454018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .of_match_table = grover_beep_match, 3464018294b53d1dae026880e45f174c1cc63b5d435Grant Likely }, 3479c1a5077fdca99356c891af37931e537dea874f5David S. Miller .probe = grover_beep_probe, 3489c1a5077fdca99356c891af37931e537dea874f5David S. Miller .remove = __devexit_p(grover_remove), 349a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller .shutdown = sparcspkr_shutdown, 350a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller}; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sparcspkr_init(void) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3544ebb24f707187196937607c60810d42f7112d7aaGrant Likely int err = platform_driver_register(&bbc_beep_driver); 355a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller 356a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller if (!err) { 3574ebb24f707187196937607c60810d42f7112d7aaGrant Likely err = platform_driver_register(&grover_beep_driver); 358a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller if (err) 3594ebb24f707187196937607c60810d42f7112d7aaGrant Likely platform_driver_unregister(&bbc_beep_driver); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 362a2bd4fd17926d715a470fbe0ebe05128ba410984David S. Miller return err; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sparcspkr_exit(void) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3674ebb24f707187196937607c60810d42f7112d7aaGrant Likely platform_driver_unregister(&bbc_beep_driver); 3684ebb24f707187196937607c60810d42f7112d7aaGrant Likely platform_driver_unregister(&grover_beep_driver); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sparcspkr_init); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sparcspkr_exit); 373