162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * m68k beeper driver for Linux 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002 Richard Zidlicky 662306a36Sopenharmony_ci * Copyright (c) 2002 Vojtech Pavlik 762306a36Sopenharmony_ci * Copyright (c) 1992 Orest Zborowski 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/input.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <asm/machdep.h> 1762306a36Sopenharmony_ci#include <asm/io.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciMODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>"); 2062306a36Sopenharmony_ciMODULE_DESCRIPTION("m68k beeper driver"); 2162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct platform_device *m68kspkr_platform_device; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci unsigned int count = 0; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (type != EV_SND) 3062306a36Sopenharmony_ci return -1; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci switch (code) { 3362306a36Sopenharmony_ci case SND_BELL: if (value) value = 1000; 3462306a36Sopenharmony_ci case SND_TONE: break; 3562306a36Sopenharmony_ci default: return -1; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (value > 20 && value < 32767) 3962306a36Sopenharmony_ci count = 1193182 / value; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci mach_beep(count, -1); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int m68kspkr_probe(struct platform_device *dev) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct input_dev *input_dev; 4962306a36Sopenharmony_ci int err; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci input_dev = input_allocate_device(); 5262306a36Sopenharmony_ci if (!input_dev) 5362306a36Sopenharmony_ci return -ENOMEM; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci input_dev->name = "m68k beeper"; 5662306a36Sopenharmony_ci input_dev->phys = "m68k/generic"; 5762306a36Sopenharmony_ci input_dev->id.bustype = BUS_HOST; 5862306a36Sopenharmony_ci input_dev->id.vendor = 0x001f; 5962306a36Sopenharmony_ci input_dev->id.product = 0x0001; 6062306a36Sopenharmony_ci input_dev->id.version = 0x0100; 6162306a36Sopenharmony_ci input_dev->dev.parent = &dev->dev; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_SND); 6462306a36Sopenharmony_ci input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); 6562306a36Sopenharmony_ci input_dev->event = m68kspkr_event; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci err = input_register_device(input_dev); 6862306a36Sopenharmony_ci if (err) { 6962306a36Sopenharmony_ci input_free_device(input_dev); 7062306a36Sopenharmony_ci return err; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci platform_set_drvdata(dev, input_dev); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int m68kspkr_remove(struct platform_device *dev) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct input_dev *input_dev = platform_get_drvdata(dev); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci input_unregister_device(input_dev); 8362306a36Sopenharmony_ci /* turn off the speaker */ 8462306a36Sopenharmony_ci m68kspkr_event(NULL, EV_SND, SND_BELL, 0); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void m68kspkr_shutdown(struct platform_device *dev) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci /* turn off the speaker */ 9262306a36Sopenharmony_ci m68kspkr_event(NULL, EV_SND, SND_BELL, 0); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic struct platform_driver m68kspkr_platform_driver = { 9662306a36Sopenharmony_ci .driver = { 9762306a36Sopenharmony_ci .name = "m68kspkr", 9862306a36Sopenharmony_ci }, 9962306a36Sopenharmony_ci .probe = m68kspkr_probe, 10062306a36Sopenharmony_ci .remove = m68kspkr_remove, 10162306a36Sopenharmony_ci .shutdown = m68kspkr_shutdown, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int __init m68kspkr_init(void) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int err; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (!mach_beep) { 10962306a36Sopenharmony_ci printk(KERN_INFO "m68kspkr: no lowlevel beep support\n"); 11062306a36Sopenharmony_ci return -ENODEV; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci err = platform_driver_register(&m68kspkr_platform_driver); 11462306a36Sopenharmony_ci if (err) 11562306a36Sopenharmony_ci return err; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci m68kspkr_platform_device = platform_device_alloc("m68kspkr", -1); 11862306a36Sopenharmony_ci if (!m68kspkr_platform_device) { 11962306a36Sopenharmony_ci err = -ENOMEM; 12062306a36Sopenharmony_ci goto err_unregister_driver; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci err = platform_device_add(m68kspkr_platform_device); 12462306a36Sopenharmony_ci if (err) 12562306a36Sopenharmony_ci goto err_free_device; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci err_free_device: 13062306a36Sopenharmony_ci platform_device_put(m68kspkr_platform_device); 13162306a36Sopenharmony_ci err_unregister_driver: 13262306a36Sopenharmony_ci platform_driver_unregister(&m68kspkr_platform_driver); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return err; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void __exit m68kspkr_exit(void) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci platform_device_unregister(m68kspkr_platform_device); 14062306a36Sopenharmony_ci platform_driver_unregister(&m68kspkr_platform_driver); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cimodule_init(m68kspkr_init); 14462306a36Sopenharmony_cimodule_exit(m68kspkr_exit); 145