Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Driver for PC-speaker like devices found on various Sparc systems.
0004  *
0005  *  Copyright (c) 2002 Vojtech Pavlik
0006  *  Copyright (c) 2002, 2006, 2008 David S. Miller (davem@davemloft.net)
0007  */
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/input.h>
0012 #include <linux/of_device.h>
0013 #include <linux/slab.h>
0014 
0015 #include <asm/io.h>
0016 
0017 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
0018 MODULE_DESCRIPTION("Sparc Speaker beeper driver");
0019 MODULE_LICENSE("GPL");
0020 
0021 struct grover_beep_info {
0022     void __iomem    *freq_regs;
0023     void __iomem    *enable_reg;
0024 };
0025 
0026 struct bbc_beep_info {
0027     u32     clock_freq;
0028     void __iomem    *regs;
0029 };
0030 
0031 struct sparcspkr_state {
0032     const char      *name;
0033     int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
0034     spinlock_t      lock;
0035     struct input_dev    *input_dev;
0036     union {
0037         struct grover_beep_info grover;
0038         struct bbc_beep_info bbc;
0039     } u;
0040 };
0041 
0042 static u32 bbc_count_to_reg(struct bbc_beep_info *info, unsigned int count)
0043 {
0044     u32 val, clock_freq = info->clock_freq;
0045     int i;
0046 
0047     if (!count)
0048         return 0;
0049 
0050     if (count <= clock_freq >> 20)
0051         return 1 << 18;
0052 
0053     if (count >= clock_freq >> 12)
0054         return 1 << 10;
0055 
0056     val = 1 << 18;
0057     for (i = 19; i >= 11; i--) {
0058         val >>= 1;
0059         if (count <= clock_freq >> i)
0060             break;
0061     }
0062 
0063     return val;
0064 }
0065 
0066 static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
0067 {
0068     struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
0069     struct bbc_beep_info *info = &state->u.bbc;
0070     unsigned int count = 0;
0071     unsigned long flags;
0072 
0073     if (type != EV_SND)
0074         return -1;
0075 
0076     switch (code) {
0077         case SND_BELL: if (value) value = 1000;
0078         case SND_TONE: break;
0079         default: return -1;
0080     }
0081 
0082     if (value > 20 && value < 32767)
0083         count = 1193182 / value;
0084 
0085     count = bbc_count_to_reg(info, count);
0086 
0087     spin_lock_irqsave(&state->lock, flags);
0088 
0089     if (count) {
0090         sbus_writeb(0x01,                 info->regs + 0);
0091         sbus_writeb(0x00,                 info->regs + 2);
0092         sbus_writeb((count >> 16) & 0xff, info->regs + 3);
0093         sbus_writeb((count >>  8) & 0xff, info->regs + 4);
0094         sbus_writeb(0x00,                 info->regs + 5);
0095     } else {
0096         sbus_writeb(0x00,                 info->regs + 0);
0097     }
0098 
0099     spin_unlock_irqrestore(&state->lock, flags);
0100 
0101     return 0;
0102 }
0103 
0104 static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
0105 {
0106     struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
0107     struct grover_beep_info *info = &state->u.grover;
0108     unsigned int count = 0;
0109     unsigned long flags;
0110 
0111     if (type != EV_SND)
0112         return -1;
0113 
0114     switch (code) {
0115         case SND_BELL: if (value) value = 1000;
0116         case SND_TONE: break;
0117         default: return -1;
0118     }
0119 
0120     if (value > 20 && value < 32767)
0121         count = 1193182 / value;
0122 
0123     spin_lock_irqsave(&state->lock, flags);
0124 
0125     if (count) {
0126         /* enable counter 2 */
0127         sbus_writeb(sbus_readb(info->enable_reg) | 3, info->enable_reg);
0128         /* set command for counter 2, 2 byte write */
0129         sbus_writeb(0xB6, info->freq_regs + 1);
0130         /* select desired HZ */
0131         sbus_writeb(count & 0xff, info->freq_regs + 0);
0132         sbus_writeb((count >> 8) & 0xff, info->freq_regs + 0);
0133     } else {
0134         /* disable counter 2 */
0135         sbus_writeb(sbus_readb(info->enable_reg) & 0xFC, info->enable_reg);
0136     }
0137 
0138     spin_unlock_irqrestore(&state->lock, flags);
0139 
0140     return 0;
0141 }
0142 
0143 static int sparcspkr_probe(struct device *dev)
0144 {
0145     struct sparcspkr_state *state = dev_get_drvdata(dev);
0146     struct input_dev *input_dev;
0147     int error;
0148 
0149     input_dev = input_allocate_device();
0150     if (!input_dev)
0151         return -ENOMEM;
0152 
0153     input_dev->name = state->name;
0154     input_dev->phys = "sparc/input0";
0155     input_dev->id.bustype = BUS_ISA;
0156     input_dev->id.vendor = 0x001f;
0157     input_dev->id.product = 0x0001;
0158     input_dev->id.version = 0x0100;
0159     input_dev->dev.parent = dev;
0160 
0161     input_dev->evbit[0] = BIT_MASK(EV_SND);
0162     input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
0163 
0164     input_dev->event = state->event;
0165 
0166     error = input_register_device(input_dev);
0167     if (error) {
0168         input_free_device(input_dev);
0169         return error;
0170     }
0171 
0172     state->input_dev = input_dev;
0173 
0174     return 0;
0175 }
0176 
0177 static void sparcspkr_shutdown(struct platform_device *dev)
0178 {
0179     struct sparcspkr_state *state = platform_get_drvdata(dev);
0180     struct input_dev *input_dev = state->input_dev;
0181 
0182     /* turn off the speaker */
0183     state->event(input_dev, EV_SND, SND_BELL, 0);
0184 }
0185 
0186 static int bbc_beep_probe(struct platform_device *op)
0187 {
0188     struct sparcspkr_state *state;
0189     struct bbc_beep_info *info;
0190     struct device_node *dp;
0191     int err = -ENOMEM;
0192 
0193     state = kzalloc(sizeof(*state), GFP_KERNEL);
0194     if (!state)
0195         goto out_err;
0196 
0197     state->name = "Sparc BBC Speaker";
0198     state->event = bbc_spkr_event;
0199     spin_lock_init(&state->lock);
0200 
0201     dp = of_find_node_by_path("/");
0202     err = -ENODEV;
0203     if (!dp)
0204         goto out_free;
0205 
0206     info = &state->u.bbc;
0207     info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
0208     of_node_put(dp);
0209     if (!info->clock_freq)
0210         goto out_free;
0211 
0212     info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
0213     if (!info->regs)
0214         goto out_free;
0215 
0216     platform_set_drvdata(op, state);
0217 
0218     err = sparcspkr_probe(&op->dev);
0219     if (err)
0220         goto out_clear_drvdata;
0221 
0222     return 0;
0223 
0224 out_clear_drvdata:
0225     of_iounmap(&op->resource[0], info->regs, 6);
0226 
0227 out_free:
0228     kfree(state);
0229 out_err:
0230     return err;
0231 }
0232 
0233 static int bbc_remove(struct platform_device *op)
0234 {
0235     struct sparcspkr_state *state = platform_get_drvdata(op);
0236     struct input_dev *input_dev = state->input_dev;
0237     struct bbc_beep_info *info = &state->u.bbc;
0238 
0239     /* turn off the speaker */
0240     state->event(input_dev, EV_SND, SND_BELL, 0);
0241 
0242     input_unregister_device(input_dev);
0243 
0244     of_iounmap(&op->resource[0], info->regs, 6);
0245 
0246     kfree(state);
0247 
0248     return 0;
0249 }
0250 
0251 static const struct of_device_id bbc_beep_match[] = {
0252     {
0253         .name = "beep",
0254         .compatible = "SUNW,bbc-beep",
0255     },
0256     {},
0257 };
0258 MODULE_DEVICE_TABLE(of, bbc_beep_match);
0259 
0260 static struct platform_driver bbc_beep_driver = {
0261     .driver = {
0262         .name = "bbcbeep",
0263         .of_match_table = bbc_beep_match,
0264     },
0265     .probe      = bbc_beep_probe,
0266     .remove     = bbc_remove,
0267     .shutdown   = sparcspkr_shutdown,
0268 };
0269 
0270 static int grover_beep_probe(struct platform_device *op)
0271 {
0272     struct sparcspkr_state *state;
0273     struct grover_beep_info *info;
0274     int err = -ENOMEM;
0275 
0276     state = kzalloc(sizeof(*state), GFP_KERNEL);
0277     if (!state)
0278         goto out_err;
0279 
0280     state->name = "Sparc Grover Speaker";
0281     state->event = grover_spkr_event;
0282     spin_lock_init(&state->lock);
0283 
0284     info = &state->u.grover;
0285     info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
0286     if (!info->freq_regs)
0287         goto out_free;
0288 
0289     info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
0290     if (!info->enable_reg)
0291         goto out_unmap_freq_regs;
0292 
0293     platform_set_drvdata(op, state);
0294 
0295     err = sparcspkr_probe(&op->dev);
0296     if (err)
0297         goto out_clear_drvdata;
0298 
0299     return 0;
0300 
0301 out_clear_drvdata:
0302     of_iounmap(&op->resource[3], info->enable_reg, 1);
0303 
0304 out_unmap_freq_regs:
0305     of_iounmap(&op->resource[2], info->freq_regs, 2);
0306 out_free:
0307     kfree(state);
0308 out_err:
0309     return err;
0310 }
0311 
0312 static int grover_remove(struct platform_device *op)
0313 {
0314     struct sparcspkr_state *state = platform_get_drvdata(op);
0315     struct grover_beep_info *info = &state->u.grover;
0316     struct input_dev *input_dev = state->input_dev;
0317 
0318     /* turn off the speaker */
0319     state->event(input_dev, EV_SND, SND_BELL, 0);
0320 
0321     input_unregister_device(input_dev);
0322 
0323     of_iounmap(&op->resource[3], info->enable_reg, 1);
0324     of_iounmap(&op->resource[2], info->freq_regs, 2);
0325 
0326     kfree(state);
0327 
0328     return 0;
0329 }
0330 
0331 static const struct of_device_id grover_beep_match[] = {
0332     {
0333         .name = "beep",
0334         .compatible = "SUNW,smbus-beep",
0335     },
0336     {},
0337 };
0338 MODULE_DEVICE_TABLE(of, grover_beep_match);
0339 
0340 static struct platform_driver grover_beep_driver = {
0341     .driver = {
0342         .name = "groverbeep",
0343         .of_match_table = grover_beep_match,
0344     },
0345     .probe      = grover_beep_probe,
0346     .remove     = grover_remove,
0347     .shutdown   = sparcspkr_shutdown,
0348 };
0349 
0350 static struct platform_driver * const drivers[] = {
0351     &bbc_beep_driver,
0352     &grover_beep_driver,
0353 };
0354 
0355 static int __init sparcspkr_init(void)
0356 {
0357     return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
0358 }
0359 
0360 static void __exit sparcspkr_exit(void)
0361 {
0362     platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
0363 }
0364 
0365 module_init(sparcspkr_init);
0366 module_exit(sparcspkr_exit);