linux/drivers/input/misc/sparcspkr.c
<<
>>
Prefs
   1/*
   2 *  Driver for PC-speaker like devices found on various Sparc systems.
   3 *
   4 *  Copyright (c) 2002 Vojtech Pavlik
   5 *  Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net)
   6 */
   7#include <linux/kernel.h>
   8#include <linux/module.h>
   9#include <linux/init.h>
  10#include <linux/input.h>
  11#include <linux/of_device.h>
  12
  13#include <asm/io.h>
  14
  15MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
  16MODULE_DESCRIPTION("Sparc Speaker beeper driver");
  17MODULE_LICENSE("GPL");
  18
  19struct grover_beep_info {
  20        void __iomem    *freq_regs;
  21        void __iomem    *enable_reg;
  22};
  23
  24struct bbc_beep_info {
  25        u32             clock_freq;
  26        void __iomem    *regs;
  27};
  28
  29struct sparcspkr_state {
  30        const char              *name;
  31        int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
  32        spinlock_t              lock;
  33        struct input_dev        *input_dev;
  34        union {
  35                struct grover_beep_info grover;
  36                struct bbc_beep_info bbc;
  37        } u;
  38};
  39
  40static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
  41{
  42        u32 val, clock_freq = info->clock_freq;
  43        int i;
  44
  45        if (!count)
  46                return 0;
  47
  48        if (count <= clock_freq >> 20)
  49                return 1 << 18;
  50
  51        if (count >= clock_freq >> 12)
  52                return 1 << 10;
  53
  54        val = 1 << 18;
  55        for (i = 19; i >= 11; i--) {
  56                val >>= 1;
  57                if (count <= clock_freq >> i)
  58                        break;
  59        }
  60
  61        return val;
  62}
  63
  64static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
  65{
  66        struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
  67        struct bbc_beep_info *info = &state->u.bbc;
  68        unsigned int count = 0;
  69        unsigned long flags;
  70
  71        if (type != EV_SND)
  72                return -1;
  73
  74        switch (code) {
  75                case SND_BELL: if (value) value = 1000;
  76                case SND_TONE: break;
  77                default: return -1;
  78        }
  79
  80        if (value > 20 && value < 32767)
  81                count = 1193182 / value;
  82
  83        count = bbc_count_to_reg(info, count);
  84
  85        spin_lock_irqsave(&state->lock, flags);
  86
  87        if (count) {
  88                outb(0x01,                 info->regs + 0);
  89                outb(0x00,                 info->regs + 2);
  90                outb((count >> 16) & 0xff, info->regs + 3);
  91                outb((count >>  8) & 0xff, info->regs + 4);
  92                outb(0x00,                 info->regs + 5);
  93        } else {
  94                outb(0x00,                 info->regs + 0);
  95        }
  96
  97        spin_unlock_irqrestore(&state->lock, flags);
  98
  99        return 0;
 100}
 101
 102static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 103{
 104        struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
 105        struct grover_beep_info *info = &state->u.grover;
 106        unsigned int count = 0;
 107        unsigned long flags;
 108
 109        if (type != EV_SND)
 110                return -1;
 111
 112        switch (code) {
 113                case SND_BELL: if (value) value = 1000;
 114                case SND_TONE: break;
 115                default: return -1;
 116        }
 117
 118        if (value > 20 && value < 32767)
 119                count = 1193182 / value;
 120
 121        spin_lock_irqsave(&state->lock, flags);
 122
 123        if (count) {
 124                /* enable counter 2 */
 125                outb(inb(info->enable_reg) | 3, info->enable_reg);
 126                /* set command for counter 2, 2 byte write */
 127                outb(0xB6, info->freq_regs + 1);
 128                /* select desired HZ */
 129                outb(count & 0xff, info->freq_regs + 0);
 130                outb((count >> 8) & 0xff, info->freq_regs + 0);
 131        } else {
 132                /* disable counter 2 */
 133                outb(inb_p(info->enable_reg) & 0xFC, info->enable_reg);
 134        }
 135
 136        spin_unlock_irqrestore(&state->lock, flags);
 137
 138        return 0;
 139}
 140
 141static int __devinit sparcspkr_probe(struct device *dev)
 142{
 143        struct sparcspkr_state *state = dev_get_drvdata(dev);
 144        struct input_dev *input_dev;
 145        int error;
 146
 147        input_dev = input_allocate_device();
 148        if (!input_dev)
 149                return -ENOMEM;
 150
 151        input_dev->name = state->name;
 152        input_dev->phys = "sparc/input0";
 153        input_dev->id.bustype = BUS_ISA;
 154        input_dev->id.vendor = 0x001f;
 155        input_dev->id.product = 0x0001;
 156        input_dev->id.version = 0x0100;
 157        input_dev->dev.parent = dev;
 158
 159        input_dev->evbit[0] = BIT_MASK(EV_SND);
 160        input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
 161
 162        input_dev->event = state->event;
 163
 164        error = input_register_device(input_dev);
 165        if (error) {
 166                input_free_device(input_dev);
 167                return error;
 168        }
 169
 170        state->input_dev = input_dev;
 171
 172        return 0;
 173}
 174
 175static int sparcspkr_shutdown(struct of_device *dev)
 176{
 177        struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
 178        struct input_dev *input_dev = state->input_dev;
 179
 180        /* turn off the speaker */
 181        state->event(input_dev, EV_SND, SND_BELL, 0);
 182
 183        return 0;
 184}
 185
 186static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match)
 187{
 188        struct sparcspkr_state *state;
 189        struct bbc_beep_info *info;
 190        struct device_node *dp;
 191        int err = -ENOMEM;
 192
 193        state = kzalloc(sizeof(*state), GFP_KERNEL);
 194        if (!state)
 195                goto out_err;
 196
 197        state->name = "Sparc BBC Speaker";
 198        state->event = bbc_spkr_event;
 199        spin_lock_init(&state->lock);
 200
 201        dp = of_find_node_by_path("/");
 202        err = -ENODEV;
 203        if (!dp)
 204                goto out_free;
 205
 206        info = &state->u.bbc;
 207        info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
 208        if (!info->clock_freq)
 209                goto out_free;
 210
 211        info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
 212        if (!info->regs)
 213                goto out_free;
 214
 215        dev_set_drvdata(&op->dev, state);
 216
 217        err = sparcspkr_probe(&op->dev);
 218        if (err)
 219                goto out_clear_drvdata;
 220
 221        return 0;
 222
 223out_clear_drvdata:
 224        dev_set_drvdata(&op->dev, NULL);
 225        of_iounmap(&op->resource[0], info->regs, 6);
 226
 227out_free:
 228        kfree(state);
 229out_err:
 230        return err;
 231}
 232
 233static int __devexit bbc_remove(struct of_device *op)
 234{
 235        struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
 236        struct input_dev *input_dev = state->input_dev;
 237        struct bbc_beep_info *info = &state->u.bbc;
 238
 239        /* turn off the speaker */
 240        state->event(input_dev, EV_SND, SND_BELL, 0);
 241
 242        input_unregister_device(input_dev);
 243
 244        of_iounmap(&op->resource[0], info->regs, 6);
 245
 246        dev_set_drvdata(&op->dev, NULL);
 247        kfree(state);
 248
 249        return 0;
 250}
 251
 252static const struct of_device_id bbc_beep_match[] = {
 253        {
 254                .name = "beep",
 255                .compatible = "SUNW,bbc-beep",
 256        },
 257        {},
 258};
 259
 260static struct of_platform_driver bbc_beep_driver = {
 261        .name           = "bbcbeep",
 262        .match_table    = bbc_beep_match,
 263        .probe          = bbc_beep_probe,
 264        .remove         = __devexit_p(bbc_remove),
 265        .shutdown       = sparcspkr_shutdown,
 266};
 267
 268static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match)
 269{
 270        struct sparcspkr_state *state;
 271        struct grover_beep_info *info;
 272        int err = -ENOMEM;
 273
 274        state = kzalloc(sizeof(*state), GFP_KERNEL);
 275        if (!state)
 276                goto out_err;
 277
 278        state->name = "Sparc Grover Speaker";
 279        state->event = grover_spkr_event;
 280        spin_lock_init(&state->lock);
 281
 282        info = &state->u.grover;
 283        info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
 284        if (!info->freq_regs)
 285                goto out_free;
 286
 287        info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
 288        if (!info->enable_reg)
 289                goto out_unmap_freq_regs;
 290
 291        dev_set_drvdata(&op->dev, state);
 292
 293        err = sparcspkr_probe(&op->dev);
 294        if (err)
 295                goto out_clear_drvdata;
 296
 297        return 0;
 298
 299out_clear_drvdata:
 300        dev_set_drvdata(&op->dev, NULL);
 301        of_iounmap(&op->resource[3], info->enable_reg, 1);
 302
 303out_unmap_freq_regs:
 304        of_iounmap(&op->resource[2], info->freq_regs, 2);
 305out_free:
 306        kfree(state);
 307out_err:
 308        return err;
 309}
 310
 311static int __devexit grover_remove(struct of_device *op)
 312{
 313        struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
 314        struct grover_beep_info *info = &state->u.grover;
 315        struct input_dev *input_dev = state->input_dev;
 316
 317        /* turn off the speaker */
 318        state->event(input_dev, EV_SND, SND_BELL, 0);
 319
 320        input_unregister_device(input_dev);
 321
 322        of_iounmap(&op->resource[3], info->enable_reg, 1);
 323        of_iounmap(&op->resource[2], info->freq_regs, 2);
 324
 325        dev_set_drvdata(&op->dev, NULL);
 326        kfree(state);
 327
 328        return 0;
 329}
 330
 331static const struct of_device_id grover_beep_match[] = {
 332        {
 333                .name = "beep",
 334                .compatible = "SUNW,smbus-beep",
 335        },
 336        {},
 337};
 338
 339static struct of_platform_driver grover_beep_driver = {
 340        .name           = "groverbeep",
 341        .match_table    = grover_beep_match,
 342        .probe          = grover_beep_probe,
 343        .remove         = __devexit_p(grover_remove),
 344        .shutdown       = sparcspkr_shutdown,
 345};
 346
 347static int __init sparcspkr_init(void)
 348{
 349        int err = of_register_driver(&bbc_beep_driver,
 350                                     &of_platform_bus_type);
 351
 352        if (!err) {
 353                err = of_register_driver(&grover_beep_driver,
 354                                         &of_platform_bus_type);
 355                if (err)
 356                        of_unregister_driver(&bbc_beep_driver);
 357        }
 358
 359        return err;
 360}
 361
 362static void __exit sparcspkr_exit(void)
 363{
 364        of_unregister_driver(&bbc_beep_driver);
 365        of_unregister_driver(&grover_beep_driver);
 366}
 367
 368module_init(sparcspkr_init);
 369module_exit(sparcspkr_exit);
 370