^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Generic IXP4xx beeper driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2005 Tower Technologies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * based on nslu2-io.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2004 Karen Spearel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Author: Alessandro Zummo <a.zummo@towertech.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Maintainers: http://www.nslu2-linux.org/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <mach/hardware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) MODULE_DESCRIPTION("ixp4xx beeper driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) MODULE_ALIAS("platform:ixp4xx-beeper");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static DEFINE_SPINLOCK(beep_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int ixp4xx_timer2_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) spin_lock_irqsave(&beep_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) gpio_direction_output(pin, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) gpio_direction_output(pin, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) gpio_direction_input(pin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *IXP4XX_OSRT2 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) spin_unlock_irqrestore(&beep_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned int pin = (unsigned int) input_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (type != EV_SND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) switch (code) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) case SND_BELL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) value = 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) case SND_TONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (value > 20 && value < 32767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) count = (ixp4xx_timer_freq / (value * 4)) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ixp4xx_spkr_control(pin, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned int pin = (unsigned int) dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* clear interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* flip the beeper output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) gpio_set_value(pin, !gpio_get_value(pin));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int ixp4xx_spkr_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) input_dev = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!input_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) input_set_drvdata(input_dev, (void *) dev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) input_dev->name = "ixp4xx beeper",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) input_dev->phys = "ixp4xx/gpio";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) input_dev->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) input_dev->id.vendor = 0x001f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) input_dev->id.product = 0x0001;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) input_dev->id.version = 0x0100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) input_dev->dev.parent = &dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) input_dev->evbit[0] = BIT_MASK(EV_SND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) input_dev->event = ixp4xx_spkr_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) irq = platform_get_irq(dev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (irq < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) err = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) goto err_free_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) err = gpio_request(dev->id, "ixp4-beeper");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) goto err_free_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) err = request_irq(irq, &ixp4xx_spkr_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) IRQF_NO_SUSPEND, "ixp4xx-beeper",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) (void *) dev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) goto err_free_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ixp4xx_timer2_irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) err = input_register_device(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) goto err_free_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) platform_set_drvdata(dev, input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) err_free_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) free_irq(irq, (void *)dev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) err_free_gpio:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) gpio_free(dev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) err_free_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) input_free_device(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static int ixp4xx_spkr_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct input_dev *input_dev = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) input_unregister_device(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* turn the speaker off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) disable_irq(ixp4xx_timer2_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ixp4xx_spkr_control(pin, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) free_irq(ixp4xx_timer2_irq, (void *)dev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) gpio_free(dev->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static void ixp4xx_spkr_shutdown(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) struct input_dev *input_dev = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* turn off the speaker */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) disable_irq(ixp4xx_timer2_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) ixp4xx_spkr_control(pin, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static struct platform_driver ixp4xx_spkr_platform_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .name = "ixp4xx-beeper",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .probe = ixp4xx_spkr_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .remove = ixp4xx_spkr_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .shutdown = ixp4xx_spkr_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) module_platform_driver(ixp4xx_spkr_platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)