Generic Raspberry Pi IR transmitters
Subsystems (28)
Sean Young
maintainerv2 cover Generic Raspberry Pi IR transmitters
These drivers are generic, but they've been tested on Raspberry Pi.
Note that the gpio-ir-recv is a separate driver, so you will end up with two /dev/lircN devices if you want a receiver and a transmitter, whilst with the lirc_rpi driver you have one /dev/lircN device.
Also note that it might be possible for the Nokia N900 to use the pwm-ir-tx driver, making ir-rx51 obsolete. The pwm-ir-tx driver is shorter and simpler.
Changes since v2:
- Removed pointless suspend handling from pwm-ir-tx
- Split out device tree bindings to separate commits
Sean Young (6):
[media] rc-core: rename input_name to device_name
[media] rc: mce kbd decoder not needed for IR TX drivers [media] rc: gpio-ir-tx: add new driver
[media] rc: pwm-ir-tx: add new driver
[media] dt-bindings: gpio-ir-tx: add support for GPIO IR Transmitter [media] dt-bindings: pwm-ir-tx: Add support for PWM IR Transmitter
.../devicetree/bindings/leds/irled/gpio-ir-tx.txt | 11 ++ .../devicetree/bindings/leds/irled/pwm-ir-tx.txt | 13 ++ MAINTAINERS | 12 ++ drivers/hid/hid-picolcd_cir.c | 2 +- drivers/media/cec/cec-core.c | 4 +- drivers/media/common/siano/smsir.c | 4 +- drivers/media/i2c/ir-kbd-i2c.c | 2 +- drivers/media/pci/bt8xx/bttv-input.c | 2 +- drivers/media/pci/cx23885/cx23885-input.c | 2 +- drivers/media/pci/cx88/cx88-input.c | 2 +- drivers/media/pci/dm1105/dm1105.c | 2 +- drivers/media/pci/mantis/mantis_common.h | 2 +- drivers/media/pci/mantis/mantis_input.c | 4 +- drivers/media/pci/saa7134/saa7134-input.c | 2 +- drivers/media/pci/smipcie/smipcie-ir.c | 4 +- drivers/media/pci/smipcie/smipcie.h | 2 +- drivers/media/pci/ttpci/budget-ci.c | 2 +- drivers/media/rc/Kconfig | 23 +++ drivers/media/rc/Makefile | 2 + drivers/media/rc/ati_remote.c | 2 +- drivers/media/rc/ene_ir.c | 4 +- drivers/media/rc/fintek-cir.c | 2 +- drivers/media/rc/gpio-ir-recv.c | 2 +- drivers/media/rc/gpio-ir-tx.c | 189 +++++++++++++++++++++ drivers/media/rc/igorplugusb.c | 2 +- drivers/media/rc/iguanair.c | 2 +- drivers/media/rc/img-ir/img-ir-hw.c | 2 +- drivers/media/rc/img-ir/img-ir-raw.c | 2 +- drivers/media/rc/imon.c | 2 +- drivers/media/rc/ir-hix5hd2.c | 2 +- drivers/media/rc/ir-mce_kbd-decoder.c | 3 + drivers/media/rc/ir-spi.c | 1 + drivers/media/rc/ite-cir.c | 2 +- drivers/media/rc/mceusb.c | 2 +- drivers/media/rc/meson-ir.c | 2 +- drivers/media/rc/mtk-cir.c | 2 +- drivers/media/rc/nuvoton-cir.c | 2 +- drivers/media/rc/pwm-ir-tx.c | 138 +++++++++++++++ drivers/media/rc/rc-loopback.c | 2 +- drivers/media/rc/rc-main.c | 8 +- drivers/media/rc/redrat3.c | 2 +- drivers/media/rc/serial_ir.c | 10 +- drivers/media/rc/sir_ir.c | 2 +- drivers/media/rc/st_rc.c | 2 +- drivers/media/rc/streamzap.c | 2 +- drivers/media/rc/sunxi-cir.c | 2 +- drivers/media/rc/ttusbir.c | 2 +- drivers/media/rc/winbond-cir.c | 2 +- drivers/media/usb/au0828/au0828-input.c | 2 +- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 5 +- drivers/media/usb/dvb-usb/dvb-usb-remote.c | 2 +- drivers/media/usb/em28xx/em28xx-input.c | 2 +- drivers/media/usb/tm6000/tm6000-input.c | 2 +- include/media/cec.h | 2 +- include/media/rc-core.h | 6 +- 55 files changed, 453 insertions(+), 62 deletions(-) create mode 100644 Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt create mode 100644 Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.txt create mode 100644 drivers/media/rc/gpio-ir-tx.c create mode 100644 drivers/media/rc/pwm-ir-tx.c
Signature · 1 line
2.9.4
Sean Young
maintainerPATCH v2 1/6 rc-core: rename input_name to device_name
When an ir-spi is registered, you get this message.
rc rc0: Unspecified device as /devices/platform/soc/3f215080.spi/spi_master/spi32766/spi32766.128/rc/rc0
"Unspecified device" refers to input_name, which makes no sense for IR TX only devices. So, rename to device_name.
Also make driver_name const char* so that no casts are needed anywhere.
Now ir-spi reports:
rc rc0: IR SPI as /devices/platform/soc/3f215080.spi/spi_master/spi32766/spi32766.128/rc/rc0
--- drivers/hid/hid-picolcd_cir.c | 2 +- drivers/media/cec/cec-core.c | 4 ++-- drivers/media/common/siano/smsir.c | 4 ++-- drivers/media/i2c/ir-kbd-i2c.c | 2 +- drivers/media/pci/bt8xx/bttv-input.c | 2 +- drivers/media/pci/cx23885/cx23885-input.c | 2 +- drivers/media/pci/cx88/cx88-input.c | 2 +- drivers/media/pci/dm1105/dm1105.c | 2 +- drivers/media/pci/mantis/mantis_common.h | 2 +- drivers/media/pci/mantis/mantis_input.c | 4 ++-- drivers/media/pci/saa7134/saa7134-input.c | 2 +- drivers/media/pci/smipcie/smipcie-ir.c | 4 ++-- drivers/media/pci/smipcie/smipcie.h | 2 +- drivers/media/pci/ttpci/budget-ci.c | 2 +- drivers/media/rc/ati_remote.c | 2 +- drivers/media/rc/ene_ir.c | 4 ++-- drivers/media/rc/fintek-cir.c | 2 +- drivers/media/rc/gpio-ir-recv.c | 2 +- drivers/media/rc/igorplugusb.c | 2 +- drivers/media/rc/iguanair.c | 2 +- drivers/media/rc/img-ir/img-ir-hw.c | 2 +- drivers/media/rc/img-ir/img-ir-raw.c | 2 +- drivers/media/rc/imon.c | 2 +- drivers/media/rc/ir-hix5hd2.c | 2 +- drivers/media/rc/ir-spi.c | 1 + drivers/media/rc/ite-cir.c | 2 +- drivers/media/rc/mceusb.c | 2 +- drivers/media/rc/meson-ir.c | 2 +- drivers/media/rc/mtk-cir.c | 2 +- drivers/media/rc/nuvoton-cir.c | 2 +- drivers/media/rc/rc-loopback.c | 2 +- drivers/media/rc/rc-main.c | 8 ++++---- drivers/media/rc/redrat3.c | 2 +- drivers/media/rc/serial_ir.c | 10 +++++----- drivers/media/rc/sir_ir.c | 2 +- drivers/media/rc/st_rc.c | 2 +- drivers/media/rc/streamzap.c | 2 +- drivers/media/rc/sunxi-cir.c | 2 +- drivers/media/rc/ttusbir.c | 2 +- drivers/media/rc/winbond-cir.c | 2 +- drivers/media/usb/au0828/au0828-input.c | 2 +- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 5 ++--- drivers/media/usb/dvb-usb/dvb-usb-remote.c | 2 +- drivers/media/usb/em28xx/em28xx-input.c | 2 +- drivers/media/usb/tm6000/tm6000-input.c | 2 +- include/media/cec.h | 2 +- include/media/rc-core.h | 6 +++--- 47 files changed, 62 insertions(+), 62 deletions(-)
drivers/hid/hid-picolcd_cir.c +1 -1
@@ -116,7 +116,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) rdev->allowed_protocols =RC_BIT_ALL_IR_DECODER ; rdev->open = picolcd_cir_open; rdev->close = picolcd_cir_close; - rdev->input_name = data->hdev->name; + rdev->device_name = data->hdev->name; rdev->input_phys = data->hdev->phys; rdev->input_id.bustype = data->hdev->bus; rdev->input_id.vendor = data->hdev->vendor;
drivers/media/cec/cec-core.c +2 -2
@@ -263,12 +263,12 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,return ERR_PTR (-ENOMEM ); } -snprintf (adap->input_name,sizeof (adap->input_name), +snprintf (adap->device_name,sizeof (adap->device_name),"RC for %s" , name);snprintf (adap->input_phys,sizeof (adap->input_phys),"%s/input0" , name); - adap->rc->input_name = adap->input_name; + adap->rc->device_name = adap->device_name; adap->rc->input_phys = adap->input_phys; adap->rc->input_id.bustype =BUS_CEC ; adap->rc->input_id.vendor =0 ;
drivers/media/common/siano/smsir.c +2 -2
@@ -73,7 +73,7 @@ int sms_ir_init(struct smscore_device_t *coredev)strlcpy (coredev->ir.phys, coredev->devpath,sizeof (coredev->ir.phys));strlcat (coredev->ir.phys,"/ir0" ,sizeof (coredev->ir.phys)); - dev->input_name = coredev->ir.name; + dev->device_name = coredev->ir.name; dev->input_phys = coredev->ir.phys; dev->dev.parent = coredev->device;
@@ -91,7 +91,7 @@ int sms_ir_init(struct smscore_device_t *coredev) dev->driver_name =MODULE_NAME ;pr_debug ("Input device (IR) %s is set for key events\n" , - dev->input_name); + dev->device_name); err =rc_register_device (dev);if (err <0 ) {
drivers/media/i2c/ir-kbd-i2c.c +1 -1
@@ -452,7 +452,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)*/ rc->input_id.bustype =BUS_I2C ; rc->input_phys = ir->phys; - rc->input_name = ir->name; + rc->device_name = ir->name;/* * Initialize the other fields of rc_dev
drivers/media/pci/bt8xx/bttv-input.c +1 -1
@@ -535,7 +535,7 @@ int bttv_input_init(struct bttv *btv)snprintf (ir->phys,sizeof (ir->phys),"pci-%s/ir0" ,pci_name (btv->c.pci)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype =BUS_PCI ; rc->input_id.version =1 ;
drivers/media/pci/cx23885/cx23885-input.c +1 -1
@@ -351,7 +351,7 @@ int cx23885_input_init(struct cx23885_dev *dev) } kernel_ir->rc = rc; - rc->input_name = kernel_ir->name; + rc->device_name = kernel_ir->name; rc->input_phys = kernel_ir->phys; rc->input_id.bustype =BUS_PCI ; rc->input_id.version =1 ;
drivers/media/pci/cx88/cx88-input.c +1 -1
@@ -464,7 +464,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)snprintf (ir->name,sizeof (ir->name),"cx88 IR (%s)" , core->board.name);snprintf (ir->phys,sizeof (ir->phys),"pci-%s/ir0" ,pci_name (pci)); - dev->input_name = ir->name; + dev->device_name = ir->name; dev->input_phys = ir->phys; dev->input_id.bustype =BUS_PCI ; dev->input_id.version =1 ;
drivers/media/pci/dm1105/dm1105.c +1 -1
@@ -748,7 +748,7 @@ static int dm1105_ir_init(struct dm1105_dev *dm1105) dev->driver_name =MODULE_NAME ; dev->map_name =RC_MAP_DM1105_NEC ; - dev->input_name ="DVB on-card IR receiver" ; + dev->device_name ="DVB on-card IR receiver" ; dev->input_phys = dm1105->ir.input_phys; dev->input_id.bustype =BUS_PCI ; dev->input_id.version =1 ;
drivers/media/pci/mantis/mantis_common.h +1 -1
@@ -176,7 +176,7 @@ struct mantis_pci {struct work_struct uart_work;struct rc_dev *rc; -char input_name[80 ]; +char device_name[80 ];char input_phys[80 ];char *rc_map_name; };
drivers/media/pci/mantis/mantis_input.c +2 -2
@@ -46,12 +46,12 @@ int mantis_input_init(struct mantis_pci *mantis) goto out; } -snprintf (mantis->input_name,sizeof (mantis->input_name), +snprintf (mantis->device_name,sizeof (mantis->device_name),"Mantis %s IR receiver" , mantis->hwconfig->model_name);snprintf (mantis->input_phys,sizeof (mantis->input_phys),"pci-%s/ir0" ,pci_name (mantis->pdev)); - dev->input_name = mantis->input_name; + dev->device_name = mantis->device_name; dev->input_phys = mantis->input_phys; dev->input_id.bustype =BUS_PCI ; dev->input_id.vendor = mantis->vendor_id;
drivers/media/pci/saa7134/saa7134-input.c +1 -1
@@ -870,7 +870,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)if (raw_decode) rc->driver_type =RC_DRIVER_IR_RAW ; - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype =BUS_PCI ; rc->input_id.version =1 ;
drivers/media/pci/smipcie/smipcie-ir.c +2 -2
@@ -188,14 +188,14 @@ int smi_ir_init(struct smi_dev *dev)return -ENOMEM ;/* init input device */ -snprintf (ir->input_name,sizeof (ir->input_name),"IR (%s)" , +snprintf (ir->device_name,sizeof (ir->device_name),"IR (%s)" , dev->info->name);snprintf (ir->input_phys,sizeof (ir->input_phys),"pci-%s/ir0" ,pci_name (dev->pci_dev)); rc_dev->driver_name ="SMI_PCIe" ; rc_dev->input_phys = ir->input_phys; - rc_dev->input_name = ir->input_name; + rc_dev->device_name = ir->device_name; rc_dev->input_id.bustype =BUS_PCI ; rc_dev->input_id.version =1 ; rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor;
drivers/media/pci/smipcie/smipcie.h +1 -1
@@ -240,7 +240,7 @@ struct smi_rc {struct smi_dev *dev;struct rc_dev *rc_dev;char input_phys[64 ]; -char input_name[64 ]; +char device_name[64 ];struct work_struct work;u8 irData[256 ];
drivers/media/pci/ttpci/budget-ci.c +1 -1
@@ -186,7 +186,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) "pci-%s/ir0", pci_name(saa->pci)); dev->driver_name =MODULE_NAME ; - dev->input_name = budget_ci->ir.name; + dev->device_name = budget_ci->ir.name; dev->input_phys = budget_ci->ir.phys; dev->input_id.bustype =BUS_PCI ; dev->input_id.version =1 ;
drivers/media/rc/ati_remote.c +1 -1
@@ -766,7 +766,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) rdev->open = ati_remote_rc_open; rdev->close = ati_remote_rc_close; - rdev->input_name = ati_remote->rc_name; + rdev->device_name = ati_remote->rc_name; rdev->input_phys = ati_remote->rc_phys;usb_to_input_id (ati_remote->udev, &rdev->input_id);
drivers/media/rc/ene_ir.c +2 -2
@@ -1060,7 +1060,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) rdev->s_idle = ene_set_idle; rdev->driver_name =ENE_DRIVER_NAME ; rdev->map_name =RC_MAP_RC6_MCE ; - rdev->input_name ="ENE eHome Infrared Remote Receiver" ; + rdev->device_name ="ENE eHome Infrared Remote Receiver" ;if (dev->hw_learning_and_tx_capable) { rdev->s_learning_mode = ene_set_learning_mode;
@@ -1070,7 +1070,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) rdev->s_tx_carrier = ene_set_tx_carrier; rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle; rdev->s_carrier_report = ene_set_carrier_report; - rdev->input_name ="ENE eHome Infrared Remote Transceiver" ; + rdev->device_name ="ENE eHome Infrared Remote Transceiver" ; } dev->rdev = rdev;
drivers/media/rc/fintek-cir.c +1 -1
@@ -532,7 +532,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id rdev->allowed_protocols =RC_BIT_ALL_IR_DECODER ; rdev->open = fintek_open; rdev->close = fintek_close; - rdev->input_name =FINTEK_DESCRIPTION ; + rdev->device_name =FINTEK_DESCRIPTION ; rdev->input_phys ="fintek/cir0" ; rdev->input_id.bustype =BUS_HOST ; rdev->input_id.vendor =VENDOR_ID_FINTEK ;
drivers/media/rc/gpio-ir-recv.c +1 -1
@@ -150,7 +150,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) } rcdev->priv = gpio_dev; - rcdev->input_name =GPIO_IR_DEVICE_NAME ; + rcdev->device_name =GPIO_IR_DEVICE_NAME ; rcdev->input_phys =GPIO_IR_DEVICE_NAME "/input0" ; rcdev->input_id.bustype =BUS_HOST ; rcdev->input_id.vendor =0x0001 ;
drivers/media/rc/igorplugusb.c +1 -1
@@ -194,7 +194,7 @@ static int igorplugusb_probe(struct usb_interface *intf,if (!rc) goto fail; - rc->input_name =DRIVER_DESC ; + rc->device_name =DRIVER_DESC ; rc->input_phys = ir->phys;usb_to_input_id (udev, &rc->input_id); rc->dev.parent = &intf->dev;
drivers/media/rc/iguanair.c +1 -1
@@ -487,7 +487,7 @@ static int iguanair_probe(struct usb_interface *intf,usb_make_path (ir->udev, ir->phys,sizeof (ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys;usb_to_input_id (ir->udev, &rc->input_id); rc->dev.parent = &intf->dev;
drivers/media/rc/img-ir/img-ir-hw.c +1 -1
@@ -1083,7 +1083,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv) rdev->priv = priv; rdev->map_name =RC_MAP_EMPTY ; rdev->allowed_protocols =img_ir_allowed_protos (priv); - rdev->input_name ="IMG Infrared Decoder" ; + rdev->device_name ="IMG Infrared Decoder" ; rdev->s_filter = img_ir_set_normal_filter; rdev->s_wakeup_filter = img_ir_set_wakeup_filter;
drivers/media/rc/img-ir/img-ir-raw.c +1 -1
@@ -117,7 +117,7 @@ int img_ir_probe_raw(struct img_ir_priv *priv) } rdev->priv = priv; rdev->map_name =RC_MAP_EMPTY ; - rdev->input_name ="IMG Infrared Decoder Raw" ; + rdev->device_name ="IMG Infrared Decoder Raw" ;/* Register raw decoder */ error =rc_register_device (rdev);
drivers/media/rc/imon.c +1 -1
@@ -2063,7 +2063,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) sizeof(ictx->phys_rdev));strlcat (ictx->phys_rdev,"/input0" ,sizeof (ictx->phys_rdev)); - rdev->input_name = ictx->name_rdev; + rdev->device_name = ictx->name_rdev; rdev->input_phys = ictx->phys_rdev;usb_to_input_id (ictx->usbdev_intf0, &rdev->input_id); rdev->dev.parent = ictx->dev;
drivers/media/rc/ir-hix5hd2.c +1 -1
@@ -249,7 +249,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) rdev->driver_name =IR_HIX5HD2_NAME ; map_name =of_get_property (node,"linux,rc-map-name" ,NULL ); rdev->map_name = map_name ?:RC_MAP_EMPTY ; - rdev->input_name =IR_HIX5HD2_NAME ; + rdev->device_name =IR_HIX5HD2_NAME ; rdev->input_phys =IR_HIX5HD2_NAME "/input0" ; rdev->input_id.bustype =BUS_HOST ; rdev->input_id.vendor =0x0001 ;
drivers/media/rc/ir-spi.c +1 -0
@@ -155,6 +155,7 @@ static int ir_spi_probe(struct spi_device *spi) idata->rc->tx_ir = ir_spi_tx; idata->rc->s_tx_carrier = ir_spi_set_tx_carrier; idata->rc->s_tx_duty_cycle = ir_spi_set_duty_cycle; + idata->rc->device_name ="IR SPI" ; idata->rc->driver_name =IR_SPI_DRIVER_NAME ; idata->rc->priv = idata; idata->spi = spi;
drivers/media/rc/ite-cir.c +1 -1
@@ -1576,7 +1576,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; } - rdev->input_name = dev_desc->model; + rdev->device_name = dev_desc->model; rdev->input_id.bustype =BUS_HOST ; rdev->input_id.vendor =PCI_VENDOR_ID_ITE ; rdev->input_id.product =0 ;
drivers/media/rc/mceusb.c +1 -1
@@ -1264,7 +1264,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)usb_make_path (ir->usbdev, ir->phys,sizeof (ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys;usb_to_input_id (ir->usbdev, &rc->input_id); rc->dev.parent = dev;
drivers/media/rc/meson-ir.c +1 -1
@@ -138,7 +138,7 @@ static int meson_ir_probe(struct platform_device *pdev) } ir->rc->priv = ir; - ir->rc->input_name =DRIVER_NAME ; + ir->rc->device_name =DRIVER_NAME ; ir->rc->input_phys =DRIVER_NAME "/input0" ; ir->rc->input_id.bustype =BUS_HOST ; map_name =of_get_property (node,"linux,rc-map-name" ,NULL );
drivers/media/rc/mtk-cir.c +1 -1
@@ -228,7 +228,7 @@ static int mtk_ir_probe(struct platform_device *pdev) } ir->rc->priv = ir; - ir->rc->input_name =MTK_IR_DEV ; + ir->rc->device_name =MTK_IR_DEV ; ir->rc->input_phys =MTK_IR_DEV "/input0" ; ir->rc->input_id.bustype =BUS_HOST ; ir->rc->input_id.vendor =0x0001 ;
drivers/media/rc/nuvoton-cir.c +1 -1
@@ -1134,7 +1134,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) rdev->tx_ir = nvt_tx_ir; rdev->s_tx_carrier = nvt_set_tx_carrier; rdev->s_wakeup_filter = nvt_ir_raw_set_wakeup_filter; - rdev->input_name ="Nuvoton w836x7hg Infrared Remote Transceiver" ; + rdev->device_name ="Nuvoton w836x7hg Infrared Remote Transceiver" ; rdev->input_phys ="nuvoton/cir0" ; rdev->input_id.bustype =BUS_HOST ; rdev->input_id.vendor =PCI_VENDOR_ID_WINBOND2 ;
drivers/media/rc/rc-loopback.c +1 -1
@@ -219,7 +219,7 @@ static int __init loop_init(void)return -ENOMEM ; } - rc->input_name ="rc-core loopback device" ; + rc->device_name ="rc-core loopback device" ; rc->input_phys ="rc-core/virtual" ; rc->input_id.bustype =BUS_VIRTUAL ; rc->input_id.version =1 ;
drivers/media/rc/rc-main.c +4 -4
@@ -530,7 +530,7 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)if (keycode !=KEY_RESERVED )IR_dprintk (1 ,"%s: scancode 0x%04x keycode 0x%02x\n" , - dev->input_name, scancode, keycode); + dev->device_name, scancode, keycode);return keycode; }
@@ -663,7 +663,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, dev->last_keycode = keycode;IR_dprintk (1 ,"%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n" , - dev->input_name, keycode, protocol, scancode); + dev->device_name, keycode, protocol, scancode);input_report_key (dev->input_dev, keycode,1 );led_trigger_event (led_feedback,LED_FULL );
@@ -1663,7 +1663,7 @@ static int rc_prepare_rx_device(struct rc_dev *dev) dev->input_dev->dev.parent = &dev->dev;memcpy (&dev->input_dev->id, &dev->input_id,sizeof (dev->input_id)); dev->input_dev->phys = dev->input_phys; - dev->input_dev->name = dev->input_name; + dev->input_dev->name = dev->device_name;return 0 ;
@@ -1759,7 +1759,7 @@ int rc_register_device(struct rc_dev *dev) path =kobject_get_path (&dev->dev.kobj,GFP_KERNEL );dev_info (&dev->dev,"%s as %s\n" , - dev->input_name ?:"Unspecified device" , path ?:"N/A" ); + dev->device_name ?:"Unspecified device" , path ?:"N/A" );kfree (path);if (dev->driver_type !=RC_DRIVER_IR_RAW_TX ) {
drivers/media/rc/redrat3.c +1 -1
@@ -951,7 +951,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)usb_make_path (rr3->udev, rr3->phys,sizeof (rr3->phys)); - rc->input_name = rr3->name; + rc->device_name = rr3->name; rc->input_phys = rr3->phys;usb_to_input_id (rr3->udev, &rc->input_id); rc->dev.parent = dev;
drivers/media/rc/serial_ir.c +5 -5
@@ -513,19 +513,19 @@ static int serial_ir_probe(struct platform_device *dev)switch (type) {case IR_HOMEBREW : - rcdev->input_name ="Serial IR type home-brew" ; + rcdev->device_name ="Serial IR type home-brew" ;break ;case IR_IRDEO : - rcdev->input_name ="Serial IR type IRdeo" ; + rcdev->device_name ="Serial IR type IRdeo" ;break ;case IR_IRDEO_REMOTE : - rcdev->input_name ="Serial IR type IRdeo remote" ; + rcdev->device_name ="Serial IR type IRdeo remote" ;break ;case IR_ANIMAX : - rcdev->input_name ="Serial IR type AnimaX" ; + rcdev->device_name ="Serial IR type AnimaX" ;break ;case IR_IGOR : - rcdev->input_name ="Serial IR type IgorPlug" ; + rcdev->device_name ="Serial IR type IgorPlug" ;break ; }
drivers/media/rc/sir_ir.c +1 -1
@@ -308,7 +308,7 @@ static int sir_ir_probe(struct platform_device *dev)if (!rcdev)return -ENOMEM ; - rcdev->input_name ="SIR IrDA port" ; + rcdev->device_name ="SIR IrDA port" ; rcdev->input_phys =KBUILD_MODNAME "/input0" ; rcdev->input_id.bustype =BUS_HOST ; rcdev->input_id.vendor =0x0001 ;
drivers/media/rc/st_rc.c +1 -1
@@ -299,7 +299,7 @@ static int st_rc_probe(struct platform_device *pdev) rdev->close = st_rc_close; rdev->driver_name =IR_ST_NAME ; rdev->map_name =RC_MAP_EMPTY ; - rdev->input_name ="ST Remote Control Receiver" ; + rdev->device_name ="ST Remote Control Receiver" ; ret =rc_register_device (rdev);if (ret <0 )
drivers/media/rc/streamzap.c +1 -1
@@ -299,7 +299,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)usb_make_path (sz->usbdev, sz->phys,sizeof (sz->phys));strlcat (sz->phys,"/input0" ,sizeof (sz->phys)); - rdev->input_name = sz->name; + rdev->device_name = sz->name; rdev->input_phys = sz->phys;usb_to_input_id (sz->usbdev, &rdev->input_id); rdev->dev.parent = dev;
drivers/media/rc/sunxi-cir.c +1 -1
@@ -215,7 +215,7 @@ static int sunxi_ir_probe(struct platform_device *pdev) } ir->rc->priv = ir; - ir->rc->input_name =SUNXI_IR_DEV ; + ir->rc->device_name =SUNXI_IR_DEV ; ir->rc->input_phys ="sunxi-ir/input0" ; ir->rc->input_id.bustype =BUS_HOST ; ir->rc->input_id.vendor =0x0001 ;
drivers/media/rc/ttusbir.c +1 -1
@@ -309,7 +309,7 @@ static int ttusbir_probe(struct usb_interface *intf,usb_make_path (tt->udev, tt->phys,sizeof (tt->phys)); - rc->input_name =DRIVER_DESC ; + rc->device_name =DRIVER_DESC ; rc->input_phys = tt->phys;usb_to_input_id (tt->udev, &rc->input_id); rc->dev.parent = &intf->dev;
drivers/media/rc/winbond-cir.c +1 -1
@@ -1068,7 +1068,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) } data->dev->driver_name =DRVNAME ; - data->dev->input_name =WBCIR_NAME ; + data->dev->device_name =WBCIR_NAME ; data->dev->input_phys ="wbcir/cir0" ; data->dev->input_id.bustype =BUS_HOST ; data->dev->input_id.vendor =PCI_VENDOR_ID_WINBOND ;
drivers/media/usb/au0828/au0828-input.c +1 -1
@@ -335,7 +335,7 @@ int au0828_rc_register(struct au0828_dev *dev)usb_make_path (dev->usbdev, ir->phys,sizeof (ir->phys));strlcat (ir->phys,"/input0" ,sizeof (ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype =BUS_USB ; rc->input_id.version =1 ;
drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +2 -3
@@ -154,13 +154,12 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) } dev->dev.parent = &d->udev->dev; - dev->input_name = d->name; + dev->device_name = d->name;usb_make_path (d->udev, d->rc_phys,sizeof (d->rc_phys));strlcat (d->rc_phys,"/ir0" ,sizeof (d->rc_phys)); dev->input_phys = d->rc_phys;usb_to_input_id (d->udev, &dev->input_id); -/* TODO: likely RC-core should took const char * */ - dev->driver_name = (char *) d->props->driver_name; + dev->driver_name = d->props->driver_name; dev->map_name = d->rc.map_name; dev->allowed_protocols = d->rc.allowed_protos; dev->change_protocol = d->rc.change_protocol;
drivers/media/usb/dvb-usb/dvb-usb-remote.c +1 -1
@@ -279,7 +279,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->change_protocol = d->props.rc.core.change_protocol; dev->allowed_protocols = d->props.rc.core.allowed_protos;usb_to_input_id (d->udev, &dev->input_id); - dev->input_name ="IR-receiver inside an USB DVB receiver" ; + dev->device_name ="IR-receiver inside an USB DVB receiver" ; dev->input_phys = d->rc_phys; dev->dev.parent = &d->udev->dev; dev->priv = d;
drivers/media/usb/em28xx/em28xx-input.c +1 -1
@@ -807,7 +807,7 @@ static int em28xx_ir_init(struct em28xx *dev)usb_make_path (udev, ir->phys,sizeof (ir->phys));strlcat (ir->phys,"/input0" ,sizeof (ir->phys)); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype =BUS_USB ; rc->input_id.version =1 ;
drivers/media/usb/tm6000/tm6000-input.c +1 -1
@@ -458,7 +458,7 @@ int tm6000_ir_init(struct tm6000_core *dev) rc_type =RC_BIT_UNKNOWN ;tm6000_ir_change_protocol (rc, &rc_type); - rc->input_name = ir->name; + rc->device_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype =BUS_USB ; rc->input_id.version =1 ;
include/media/cec.h +1 -1
@@ -184,7 +184,7 @@ struct cec_adapter {u16 phys_addrs[15 ];u32 sequence; -char input_name[32 ]; +char device_name[32 ];char input_phys[32 ];char input_drv[32 ]; };
include/media/rc-core.h +3 -3
@@ -72,7 +72,7 @@ enum rc_filter_type {* @dev: driver model's view of this device * @managed_alloc: devm_rc_allocate_device was used to create rc_dev * @sysfs_groups: sysfs attribute groups -* @input_name: name of the input child device +* @device_name: name of the rc child device * @input_phys: physical path to the input child device * @input_id: id of the input child device (struct input_id) * @driver_name: name of the hardware driver which registered this device
@@ -138,10 +138,10 @@ struct rc_dev {struct device dev;bool managed_alloc;const struct attribute_group *sysfs_groups[5 ]; -const char *input_name; +const char *device_name;const char *input_phys;struct input_id input_id; -char *driver_name; +const char *driver_name;const char *map_name;struct rc_map rc_map;struct mutex lock;
Signature · 1 line
2.9.4
Sean Young
maintainerPATCH v2 2/6 rc: mce kbd decoder not needed for IR TX drivers
In reply to Sean YoungWithout this patch, an input device is created which is not necessary.
--- drivers/media/rc/ir-mce_kbd-decoder.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/media/rc/ir-mce_kbd-decoder.c +3 -0
@@ -358,6 +358,9 @@ static int ir_mce_kbd_register(struct rc_dev *dev)struct input_dev *idev;int i, ret; +if (dev->driver_type ==RC_DRIVER_IR_RAW_TX ) +return 0 ; + idev =input_allocate_device ();if (!idev)return -ENOMEM ;
Signature · 1 line
2.9.4
Sean Young
maintainerPATCH v2 3/6 rc: gpio-ir-tx: add new driver
In reply to Sean YoungThis is a simple bit-banging GPIO IR TX driver.
--- MAINTAINERS | 6 ++ drivers/media/rc/Kconfig | 11 +++ drivers/media/rc/Makefile | 1 + drivers/media/rc/gpio-ir-tx.c | 189 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 drivers/media/rc/gpio-ir-tx.c
MAINTAINERS +6 -0
@@ -5667,6 +5667,12 @@ L: [email protected] S: Maintained F: drivers/input/touchscreen/goodix.c +GPIO IR Transmitter +M: Sean Young <[email protected]> +L: [email protected] +S: Maintained +F: drivers/media/rc/gpio-ir-tx.c + GPIO MOCKUP DRIVER M: Bamvor Jian Zhang <[email protected]> L: [email protected]
drivers/media/rc/Kconfig +11 -0
@@ -399,6 +399,17 @@ config IR_GPIO_CIR To compile this driver as a module, choose M here: the module will be called gpio-ir-recv. +config IR_GPIO_TX + tristate "GPIO IR bit banging transmitter" + depends on RC_CORE + depends on LIRC + ---help--- + Say Y if you want to a GPIO based IR transmitter. This is a + bit banging driver. + + To compile this driver as a module, choose M here: the module will + be called gpio-ir-tx. + config RC_ST tristate "ST remote control receiver" depends on RC_CORE
drivers/media/rc/Makefile +1 -0
@@ -32,6 +32,7 @@ obj-$(CONFIG_IR_STREAMZAP) += streamzap.o obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o +obj-$(CONFIG_IR_GPIO_TX) += gpio-ir-tx.o obj-$(CONFIG_IR_IGORPLUGUSB) += igorplugusb.o obj-$(CONFIG_IR_IGUANA) += iguanair.o obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
drivers/media/rc/gpio-ir-tx.c new file +189 -0
189 lines not on this page · raw message
Signature · 1 line
2.9.4
Re: [PATCH v2 3/6] [media] rc: gpio-ir-tx: add new driver
Hi Sean,
Quoted 1 line · Sean Young
This is a simple bit-banging GPIO IR TX driver.
thanks a lot for the driver, this is highly appreciated!
I tested the patch series on a RPi2, against RPi downstream kernel 4.13-rc1, and noticed an issue: the polarity of the gpio seems to be reversed.
Other than the polarity issue the driver seems to work fine - at least on the scope screen. Didn't have an IR transmitter to do some real tests yet.
I've configured the gpio as active high:
gpio_ir_tx: gpio-ir-transmitter {
compatible = "gpio-ir-tx";
gpios = <&gpio 18 0>;
};However, when loading the gpio-ir-tx driver the gpio pin changed to 3.3V. I did some tests with ir-ctl -S, idle state of the signal was 3.3V, active state 0V.
I think it's better to use the descriptor based gpio functions instead of the legacy number based ones. That'll simplify the driver and it can delegate polarity handling to gpiod.
Proposed changes and comments are inline. I've also included the patch against your patch that I've been testing with at the end of the message.
Quoted 12 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0@@ -0,0 +1,189 @@ +/* +* Copyright (C) 2017 Sean Young <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, or +* (at your option) any later version.
drivers/media/rc/gpio-ir-tx.c line 16
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio.h>
use linux/gpio/consumer.h instead of linux/gpio.h
drivers/media/rc/gpio-ir-tx.c line 20
Quoted 4 lines
drivers/media/rc/gpio-ir-tx.c new file +4
-0+#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h>
of_gpio.h can be dropped
drivers/media/rc/gpio-ir-tx.c line 29
Quoted 9 lines
drivers/media/rc/gpio-ir-tx.c new file +9
-0+#include <linux/platform_device.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "gpio-ir-tx" +#define DEVICE_NAME "GPIO Bit Banging IR Transmitter" + +struct gpio_ir { +int gpio_nr; +bool active_low;
Replace these 2 fields with
struct gpio_desc *gpio;
Quoted 66 lines
drivers/media/rc/gpio-ir-tx.c new file +66
-0+unsigned int carrier; +unsigned int duty_cycle; +/* we need a spinlock to hold the cpu while transmitting */ +spinlock_t lock; +}; + +static const struct of_device_id gpio_ir_tx_of_match[] = { + { .compatible ="gpio-ir-tx" , }, + { }, +}; +MODULE_DEVICE_TABLE (of, gpio_ir_tx_of_match); + +static int gpio_ir_tx_set_duty_cycle (struct rc_dev *dev,u32 duty_cycle) +{ +struct gpio_ir *gpio_ir = dev->priv; + + gpio_ir->duty_cycle = duty_cycle; + +return 0 ; +} + +static int gpio_ir_tx_set_carrier (struct rc_dev *dev,u32 carrier) +{ +struct gpio_ir *gpio_ir = dev->priv; + +if (!carrier) +return -EINVAL ; + + gpio_ir->carrier = carrier; + +return 0 ; +} + +static int gpio_ir_tx (struct rc_dev *dev,unsigned int *txbuf, +unsigned int count) +{ +struct gpio_ir *gpio_ir = dev->priv; +unsigned long flags; +ktime_t edge; +/* +* delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on +* m68k ndelay(s64) does not compile; so use s32 rather than s64. +*/ +s32 delta; +int i; +unsigned int pulse, space; + +/* Ensure the dividend fits into 32 bit */ + pulse =DIV_ROUND_CLOSEST (gpio_ir->duty_cycle * (NSEC_PER_SEC /100 ), + gpio_ir->carrier); + space =DIV_ROUND_CLOSEST ((100 - gpio_ir->duty_cycle) * + (NSEC_PER_SEC /100 ), gpio_ir->carrier); + +spin_lock_irqsave (&gpio_ir->lock, flags); + + edge =ktime_get (); + +for (i =0 ; i < count; i++) { +if (i %2 ) { +// space + edge =ktime_add_us (edge, txbuf[i]); + delta =ktime_us_delta (edge,ktime_get ()); +if (delta >10 ) { +spin_unlock_irqrestore (&gpio_ir->lock, flags); +usleep_range (delta, delta +10 ); +spin_lock_irqsave (&gpio_ir->lock, flags);
drivers/media/rc/gpio-ir-tx.c line 105
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ }else if (delta >0 ) { +udelay (delta); + } + }else { +// pulse +ktime_t last =ktime_add_us (edge, txbuf[i]); + +while (ktime_get () < last) { +gpio_set_value (gpio_ir->gpio_nr, + gpio_ir->active_low);
gpiod_set_value(gpio_ir->gpio, 1);
drivers/media/rc/gpio-ir-tx.c line 111
Quoted 6 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0+ edge += pulse; + delta = edge -ktime_get (); +if (delta >0 ) +ndelay (delta); +gpio_set_value (gpio_ir->gpio_nr, + !gpio_ir->active_low);
gpiod_set_value(gpio_ir->gpio, 0);
Quoted 11 lines
drivers/media/rc/gpio-ir-tx.c new file +11
-0+ edge += space; + delta = edge -ktime_get (); +if (delta >0 ) +ndelay (delta); + } + + edge = last; + } + } + +spin_unlock_irqrestore (&gpio_ir->lock, flags);
drivers/media/rc/gpio-ir-tx.c line 132
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ +return count; +} + +static int gpio_ir_tx_probe (struct platform_device *pdev) +{ +struct gpio_ir *gpio_ir; +struct rc_dev *rcdev; +enum of_gpio_flags flags; +int rc, gpio;
Flags can be dropped, gpio as well.
drivers/media/rc/gpio-ir-tx.c line 140
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +8
-0+ + gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); +if (gpio <0 ) { +if (gpio != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , + gpio); +return -EINVAL ; + }
Drop this and move getting the gpio a bit down so we don't need a temp variable.
drivers/media/rc/gpio-ir-tx.c line 148
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +8
-0+ + gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL ); +if (!gpio_ir) +return -ENOMEM ; + + rcdev =devm_rc_allocate_device (&pdev->dev,RC_DRIVER_IR_RAW_TX ); +if (!rcdev) +return -ENOMEM ;
get the gpio here, configure it to output with logical low (idle) level and store it in gpio_ir:
gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
if (IS_ERR(gpio_ir->gpio)) {
if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get gpio (%ld)\n",
PTR_ERR(gpio_ir->gpio));
return PTR_ERR(gpio_ir->gpio);
}drivers/media/rc/gpio-ir-tx.c line 158
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ + rcdev->priv = gpio_ir; + rcdev->driver_name =DRIVER_NAME ; + rcdev->device_name =DEVICE_NAME ; + rcdev->tx_ir = gpio_ir_tx; + rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; + rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; + + gpio_ir->gpio_nr = gpio; + gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ;
drop gpio_nr and active_low
drivers/media/rc/gpio-ir-tx.c line 169
Quoted 11 lines
drivers/media/rc/gpio-ir-tx.c new file +11
-0+ gpio_ir->carrier =38000 ; + gpio_ir->duty_cycle =50 ; +spin_lock_init (&gpio_ir->lock); + + rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); +if (rc <0 ) +return rc; + + rc =gpio_direction_output (gpio, !gpio_ir->active_low); +if (rc <0 ) +return rc;
drop devm_gpio_request and gpio_direction_output, that is already handled by devm_gpiod_get.
Quoted 22 lines
drivers/media/rc/gpio-ir-tx.c new file +20
-0+ + rc =devm_rc_register_device (&pdev->dev, rcdev); +if (rc <0 ) +dev_err (&pdev->dev,"failed to register rc device\n" ); + +return rc; +} + +static struct platform_driver gpio_ir_tx_driver = { + .probe = gpio_ir_tx_probe, + .driver = { + .name =DRIVER_NAME , + .of_match_table =of_match_ptr (gpio_ir_tx_of_match), + }, +}; +module_platform_driver (gpio_ir_tx_driver); + +MODULE_DESCRIPTION ("GPIO Bit Banging IR Transmitter" ); +MODULE_AUTHOR ("Sean Young <[email protected]>" ); +MODULE_LICENSE ("GPL" );Signature · 1 line
2.9.4
so long,
Hias
---
drivers/media/rc/gpio-ir-tx.c +13 -28
@@ -13,11 +13,10 @@#include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <media/rc-core.h>
@@ -25,8 +24,7 @@#define DEVICE_NAME "GPIO Bit Banging IR Transmitter"struct gpio_ir { -int gpio_nr; -bool active_low; +struct gpio_desc *gpio;unsigned int carrier;unsigned int duty_cycle;/* we need a spinlock to hold the cpu while transmitting */
@@ -101,14 +99,12 @@ static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,ktime_t last =ktime_add_us (edge, txbuf[i]);while (ktime_get () < last) { -gpio_set_value (gpio_ir->gpio_nr, - gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,1 ); edge += pulse; delta = edge -ktime_get ();if (delta >0 )ndelay (delta); -gpio_set_value (gpio_ir->gpio_nr, - !gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,0 ); edge += space; delta = edge -ktime_get ();if (delta >0 )
@@ -128,16 +124,7 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) {struct gpio_ir *gpio_ir;struct rc_dev *rcdev; -enum of_gpio_flags flags; -int rc, gpio; - - gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); -if (gpio <0 ) { -if (gpio != -EPROBE_DEFER ) -dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , - gpio); -return -EINVAL ; - } +int rc; gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL );if (!gpio_ir)
@@ -147,6 +134,14 @@ static int gpio_ir_tx_probe(struct platform_device *pdev)if (!rcdev)return -ENOMEM ; + gpio_ir->gpio =devm_gpiod_get (&pdev->dev,NULL ,GPIOD_OUT_LOW ); +if (IS_ERR (gpio_ir->gpio)) { +if (PTR_ERR (gpio_ir->gpio) != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio (%ld)\n" , +PTR_ERR (gpio_ir->gpio)); +return PTR_ERR (gpio_ir->gpio); + } + rcdev->priv = gpio_ir; rcdev->driver_name =DRIVER_NAME ; rcdev->device_name =DEVICE_NAME ;
@@ -154,20 +149,10 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; - gpio_ir->gpio_nr = gpio; - gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ; gpio_ir->carrier =38000 ; gpio_ir->duty_cycle =50 ;spin_lock_init (&gpio_ir->lock); - rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); -if (rc <0 ) -return rc; - - rc =gpio_direction_output (gpio, !gpio_ir->active_low); -if (rc <0 ) -return rc; - rc =devm_rc_register_device (&pdev->dev, rcdev);if (rc <0 )dev_err (&pdev->dev,"failed to register rc device\n" );
Re: [PATCH v2 3/6] [media] rc: gpio-ir-tx: add new driver
Hi Sean,
Quoted 7 lines · Matthias Reichl
Hi Sean,
Quoted 1 line · Sean Young
This is a simple bit-banging GPIO IR TX driver.
thanks a lot for the driver, this is highly appreciated!
Quoted 7 lines
I tested the patch series on a RPi2, against RPi downstream kernel 4.13-rc1, and noticed an issue: the polarity of the gpio seems to be reversed.
Other than the polarity issue the driver seems to work fine - at least on the scope screen. Didn't have an IR transmitter to do some real tests yet.
I've now run a functional test and it worked fine.
I tested with your patch and my proposed changes, using an active-high IR transmitter and ir-ctl -S rc5:... to send rc-5 codes and another RPi with gpio-ir-recv to receive/decode them.
so long & thanks a lot,
Hias
Quoted 362 lines
I've configured the gpio as active high:
gpio_ir_tx: gpio-ir-transmitter { compatible = "gpio-ir-tx"; gpios = <&gpio 18 0>; };However, when loading the gpio-ir-tx driver the gpio pin changed to 3.3V. I did some tests with ir-ctl -S, idle state of the signal was 3.3V, active state 0V.
I think it's better to use the descriptor based gpio functions instead of the legacy number based ones. That'll simplify the driver and it can delegate polarity handling to gpiod.
Proposed changes and comments are inline. I've also included the patch against your patch that I've been testing with at the end of the message.
Quoted 12 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0@@ -0,0 +1,189 @@ +/* +* Copyright (C) 2017 Sean Young <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, or +* (at your option) any later version. drivers/media/rc/gpio-ir-tx.c line 16
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio.h> use
linux/gpio/consumer.hinstead oflinux/gpio.hdrivers/media/rc/gpio-ir-tx.c line 20
Quoted 4 lines
drivers/media/rc/gpio-ir-tx.c new file +4
-0+#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h>
of_gpio.hcan be droppeddrivers/media/rc/gpio-ir-tx.c line 29
Quoted 9 lines
drivers/media/rc/gpio-ir-tx.c new file +9
-0+#include <linux/platform_device.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "gpio-ir-tx" +#define DEVICE_NAME "GPIO Bit Banging IR Transmitter" + +struct gpio_ir { +int gpio_nr; +bool active_low;Replace these 2 fields with
struct gpio_desc *gpio;Quoted 66 lines
drivers/media/rc/gpio-ir-tx.c new file +66
-0+unsigned int carrier; +unsigned int duty_cycle; +/* we need a spinlock to hold the cpu while transmitting */ +spinlock_t lock; +}; + +static const struct of_device_id gpio_ir_tx_of_match[] = { + { .compatible ="gpio-ir-tx" , }, + { }, +}; +MODULE_DEVICE_TABLE (of, gpio_ir_tx_of_match); + +static int gpio_ir_tx_set_duty_cycle (struct rc_dev *dev,u32 duty_cycle) +{ +struct gpio_ir *gpio_ir = dev->priv; + + gpio_ir->duty_cycle = duty_cycle; + +return 0 ; +} + +static int gpio_ir_tx_set_carrier (struct rc_dev *dev,u32 carrier) +{ +struct gpio_ir *gpio_ir = dev->priv; + +if (!carrier) +return -EINVAL ; + + gpio_ir->carrier = carrier; + +return 0 ; +} + +static int gpio_ir_tx (struct rc_dev *dev,unsigned int *txbuf, +unsigned int count) +{ +struct gpio_ir *gpio_ir = dev->priv; +unsigned long flags; +ktime_t edge; +/* +* delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on +* m68k ndelay(s64) does not compile; so use s32 rather than s64. +*/ +s32 delta; +int i; +unsigned int pulse, space; + +/* Ensure the dividend fits into 32 bit */ + pulse =DIV_ROUND_CLOSEST (gpio_ir->duty_cycle * (NSEC_PER_SEC /100 ), + gpio_ir->carrier); + space =DIV_ROUND_CLOSEST ((100 - gpio_ir->duty_cycle) * + (NSEC_PER_SEC /100 ), gpio_ir->carrier); + +spin_lock_irqsave (&gpio_ir->lock, flags); + + edge =ktime_get (); + +for (i =0 ; i < count; i++) { +if (i %2 ) { +// space + edge =ktime_add_us (edge, txbuf[i]); + delta =ktime_us_delta (edge,ktime_get ()); +if (delta >10 ) { +spin_unlock_irqrestore (&gpio_ir->lock, flags); +usleep_range (delta, delta +10 ); +spin_lock_irqsave (&gpio_ir->lock, flags);drivers/media/rc/gpio-ir-tx.c line 105
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ }else if (delta >0 ) { +udelay (delta); + } + }else { +// pulse +ktime_t last =ktime_add_us (edge, txbuf[i]); + +while (ktime_get () < last) { +gpio_set_value (gpio_ir->gpio_nr, + gpio_ir->active_low);gpiod_set_value(gpio_ir->gpio, 1);drivers/media/rc/gpio-ir-tx.c line 111
Quoted 6 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0+ edge += pulse; + delta = edge -ktime_get (); +if (delta >0 ) +ndelay (delta); +gpio_set_value (gpio_ir->gpio_nr, + !gpio_ir->active_low);gpiod_set_value(gpio_ir->gpio, 0);Quoted 11 lines
drivers/media/rc/gpio-ir-tx.c new file +11
-0+ edge += space; + delta = edge -ktime_get (); +if (delta >0 ) +ndelay (delta); + } + + edge = last; + } + } + +spin_unlock_irqrestore (&gpio_ir->lock, flags);drivers/media/rc/gpio-ir-tx.c line 132
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ +return count; +} + +static int gpio_ir_tx_probe (struct platform_device *pdev) +{ +struct gpio_ir *gpio_ir; +struct rc_dev *rcdev; +enum of_gpio_flags flags; +int rc, gpio;Flags can be dropped, gpio as well.
drivers/media/rc/gpio-ir-tx.c line 140
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +8
-0+ + gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); +if (gpio <0 ) { +if (gpio != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , + gpio); +return -EINVAL ; + }Drop this and move getting the gpio a bit down so we don't need a temp variable.
drivers/media/rc/gpio-ir-tx.c line 148
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +8
-0+ + gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL ); +if (!gpio_ir) +return -ENOMEM ; + + rcdev =devm_rc_allocate_device (&pdev->dev,RC_DRIVER_IR_RAW_TX ); +if (!rcdev) +return -ENOMEM ;get the gpio here, configure it to output with logical low (idle) level and store it in
gpio_ir:gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); if (IS_ERR(gpio_ir->gpio)) { if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to get gpio (%ld)\n", PTR_ERR(gpio_ir->gpio)); return PTR_ERR(gpio_ir->gpio); }drivers/media/rc/gpio-ir-tx.c line 158
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ + rcdev->priv = gpio_ir; + rcdev->driver_name =DRIVER_NAME ; + rcdev->device_name =DEVICE_NAME ; + rcdev->tx_ir = gpio_ir_tx; + rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; + rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; + + gpio_ir->gpio_nr = gpio; + gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ;drop
gpio_nrandactive_lowdrivers/media/rc/gpio-ir-tx.c line 169
Quoted 11 lines
drivers/media/rc/gpio-ir-tx.c new file +11
-0+ gpio_ir->carrier =38000 ; + gpio_ir->duty_cycle =50 ; +spin_lock_init (&gpio_ir->lock); + + rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); +if (rc <0 ) +return rc; + + rc =gpio_direction_output (gpio, !gpio_ir->active_low); +if (rc <0 ) +return rc;drop
devm_gpio_requestandgpio_direction_output, that is already handled bydevm_gpiod_get.Quoted 22 lines
drivers/media/rc/gpio-ir-tx.c new file +20
-0+ + rc =devm_rc_register_device (&pdev->dev, rcdev); +if (rc <0 ) +dev_err (&pdev->dev,"failed to register rc device\n" ); + +return rc; +} + +static struct platform_driver gpio_ir_tx_driver = { + .probe = gpio_ir_tx_probe, + .driver = { + .name =DRIVER_NAME , + .of_match_table =of_match_ptr (gpio_ir_tx_of_match), + }, +}; +module_platform_driver (gpio_ir_tx_driver); + +MODULE_DESCRIPTION ("GPIO Bit Banging IR Transmitter" ); +MODULE_AUTHOR ("Sean Young <[email protected]>" ); +MODULE_LICENSE ("GPL" );Signature · 1 line
2.9.4so long,
Hias
---drivers/media/rc/gpio-ir-tx.c +13
-28@@ -13,11 +13,10 @@#include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <media/rc-core.h> @@ -25,8 +24,7 @@#define DEVICE_NAME "GPIO Bit Banging IR Transmitter"struct gpio_ir { -int gpio_nr; -bool active_low; +struct gpio_desc *gpio;unsigned int carrier;unsigned int duty_cycle;/* we need a spinlock to hold the cpu while transmitting */ @@ -101,14 +99,12 @@ static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,ktime_t last =ktime_add_us (edge, txbuf[i]);while (ktime_get () < last) { -gpio_set_value (gpio_ir->gpio_nr, - gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,1 ); edge += pulse; delta = edge -ktime_get ();if (delta >0 )ndelay (delta); -gpio_set_value (gpio_ir->gpio_nr, - !gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,0 ); edge += space; delta = edge -ktime_get ();if (delta >0 )@@ -128,16 +124,7 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) {struct gpio_ir *gpio_ir;struct rc_dev *rcdev; -enum of_gpio_flags flags; -int rc, gpio; - - gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); -if (gpio <0 ) { -if (gpio != -EPROBE_DEFER ) -dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , - gpio); -return -EINVAL ; - } +int rc; gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL );if (!gpio_ir)@@ -147,6 +134,14 @@ static int gpio_ir_tx_probe(struct platform_device *pdev)if (!rcdev)return -ENOMEM ; + gpio_ir->gpio =devm_gpiod_get (&pdev->dev,NULL ,GPIOD_OUT_LOW ); +if (IS_ERR (gpio_ir->gpio)) { +if (PTR_ERR (gpio_ir->gpio) != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio (%ld)\n" , +PTR_ERR (gpio_ir->gpio)); +return PTR_ERR (gpio_ir->gpio); + } + rcdev->priv = gpio_ir; rcdev->driver_name =DRIVER_NAME ; rcdev->device_name =DEVICE_NAME ;@@ -154,20 +149,10 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; - gpio_ir->gpio_nr = gpio; - gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ; gpio_ir->carrier =38000 ; gpio_ir->duty_cycle =50 ;spin_lock_init (&gpio_ir->lock); - rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); -if (rc <0 ) -return rc; - - rc =gpio_direction_output (gpio, !gpio_ir->active_low); -if (rc <0 ) -return rc; - rc =devm_rc_register_device (&pdev->dev, rcdev);if (rc <0 )dev_err (&pdev->dev,"failed to register rc device\n" );
Sean Young
maintainerRe: [PATCH v2 3/6] [media] rc: gpio-ir-tx: add new driver
In reply to Matthias ReichlHi Matthias,
Quoted 22 lines · Matthias Reichl
Hi Sean,
Quoted 1 line · Sean Young
This is a simple bit-banging GPIO IR TX driver.
thanks a lot for the driver, this is highly appreciated!
I tested the patch series on a RPi2, against RPi downstream kernel 4.13-rc1, and noticed an issue: the polarity of the gpio seems to be reversed.
Other than the polarity issue the driver seems to work fine - at least on the scope screen. Didn't have an IR transmitter to do some real tests yet.
I've configured the gpio as active high:
gpio_ir_tx: gpio-ir-transmitter { compatible = "gpio-ir-tx"; gpios = <&gpio 18 0>; };
Quoted 7 lines
However, when loading the gpio-ir-tx driver the gpio pin changed to 3.3V. I did some tests with ir-ctl -S, idle state of the signal was 3.3V, active state 0V.
I think it's better to use the descriptor based gpio functions instead of the legacy number based ones. That'll simplify the driver and it can delegate polarity handling to gpiod.
You're absolutely right, this is much nicer and makes the driver shorter.
Quoted 3 lines
Proposed changes and comments are inline. I've also included the patch against your patch that I've been testing with at the end of the message.
I agree with all your comments. However, we need a Signed-off-by:
line to use your patch, thank you.
Regards,
Sean
Quoted 232 lines
Quoted 13 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0@@ -0,0 +1,189 @@ +/* +* Copyright (C) 2017 Sean Young <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, or +* (at your option) any later version. drivers/media/rc/gpio-ir-tx.c line 16
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio.h> use
linux/gpio/consumer.hinstead oflinux/gpio.hdrivers/media/rc/gpio-ir-tx.c line 20
Quoted 4 lines
drivers/media/rc/gpio-ir-tx.c new file +4
-0+#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h>
of_gpio.hcan be droppeddrivers/media/rc/gpio-ir-tx.c line 29
Quoted 9 lines
drivers/media/rc/gpio-ir-tx.c new file +9
-0+#include <linux/platform_device.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "gpio-ir-tx" +#define DEVICE_NAME "GPIO Bit Banging IR Transmitter" + +struct gpio_ir { +int gpio_nr; +bool active_low;Replace these 2 fields with
struct gpio_desc *gpio;Quoted 66 lines
drivers/media/rc/gpio-ir-tx.c new file +66
-0+unsigned int carrier; +unsigned int duty_cycle; +/* we need a spinlock to hold the cpu while transmitting */ +spinlock_t lock; +}; + +static const struct of_device_id gpio_ir_tx_of_match[] = { + { .compatible ="gpio-ir-tx" , }, + { }, +}; +MODULE_DEVICE_TABLE (of, gpio_ir_tx_of_match); + +static int gpio_ir_tx_set_duty_cycle (struct rc_dev *dev,u32 duty_cycle) +{ +struct gpio_ir *gpio_ir = dev->priv; + + gpio_ir->duty_cycle = duty_cycle; + +return 0 ; +} + +static int gpio_ir_tx_set_carrier (struct rc_dev *dev,u32 carrier) +{ +struct gpio_ir *gpio_ir = dev->priv; + +if (!carrier) +return -EINVAL ; + + gpio_ir->carrier = carrier; + +return 0 ; +} + +static int gpio_ir_tx (struct rc_dev *dev,unsigned int *txbuf, +unsigned int count) +{ +struct gpio_ir *gpio_ir = dev->priv; +unsigned long flags; +ktime_t edge; +/* +* delta should never exceed 0.5 seconds (IR_MAX_DURATION) and on +* m68k ndelay(s64) does not compile; so use s32 rather than s64. +*/ +s32 delta; +int i; +unsigned int pulse, space; + +/* Ensure the dividend fits into 32 bit */ + pulse =DIV_ROUND_CLOSEST (gpio_ir->duty_cycle * (NSEC_PER_SEC /100 ), + gpio_ir->carrier); + space =DIV_ROUND_CLOSEST ((100 - gpio_ir->duty_cycle) * + (NSEC_PER_SEC /100 ), gpio_ir->carrier); + +spin_lock_irqsave (&gpio_ir->lock, flags); + + edge =ktime_get (); + +for (i =0 ; i < count; i++) { +if (i %2 ) { +// space + edge =ktime_add_us (edge, txbuf[i]); + delta =ktime_us_delta (edge,ktime_get ()); +if (delta >10 ) { +spin_unlock_irqrestore (&gpio_ir->lock, flags); +usleep_range (delta, delta +10 ); +spin_lock_irqsave (&gpio_ir->lock, flags);drivers/media/rc/gpio-ir-tx.c line 105
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ }else if (delta >0 ) { +udelay (delta); + } + }else { +// pulse +ktime_t last =ktime_add_us (edge, txbuf[i]); + +while (ktime_get () < last) { +gpio_set_value (gpio_ir->gpio_nr, + gpio_ir->active_low);gpiod_set_value(gpio_ir->gpio, 1);drivers/media/rc/gpio-ir-tx.c line 111
Quoted 6 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0+ edge += pulse; + delta = edge -ktime_get (); +if (delta >0 ) +ndelay (delta); +gpio_set_value (gpio_ir->gpio_nr, + !gpio_ir->active_low);gpiod_set_value(gpio_ir->gpio, 0);Quoted 11 lines
drivers/media/rc/gpio-ir-tx.c new file +11
-0+ edge += space; + delta = edge -ktime_get (); +if (delta >0 ) +ndelay (delta); + } + + edge = last; + } + } + +spin_unlock_irqrestore (&gpio_ir->lock, flags);drivers/media/rc/gpio-ir-tx.c line 132
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ +return count; +} + +static int gpio_ir_tx_probe (struct platform_device *pdev) +{ +struct gpio_ir *gpio_ir; +struct rc_dev *rcdev; +enum of_gpio_flags flags; +int rc, gpio;Flags can be dropped, gpio as well.
drivers/media/rc/gpio-ir-tx.c line 140
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +8
-0+ + gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); +if (gpio <0 ) { +if (gpio != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , + gpio); +return -EINVAL ; + }Drop this and move getting the gpio a bit down so we don't need a temp variable.
drivers/media/rc/gpio-ir-tx.c line 148
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +8
-0+ + gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL ); +if (!gpio_ir) +return -ENOMEM ; + + rcdev =devm_rc_allocate_device (&pdev->dev,RC_DRIVER_IR_RAW_TX ); +if (!rcdev) +return -ENOMEM ;get the gpio here, configure it to output with logical low (idle) level and store it in
gpio_ir:gpio_ir->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW); if (IS_ERR(gpio_ir->gpio)) { if (PTR_ERR(gpio_ir->gpio) != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to get gpio (%ld)\n", PTR_ERR(gpio_ir->gpio)); return PTR_ERR(gpio_ir->gpio); }drivers/media/rc/gpio-ir-tx.c line 158
Quoted 10 lines
drivers/media/rc/gpio-ir-tx.c new file +10
-0+ + rcdev->priv = gpio_ir; + rcdev->driver_name =DRIVER_NAME ; + rcdev->device_name =DEVICE_NAME ; + rcdev->tx_ir = gpio_ir_tx; + rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; + rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; + + gpio_ir->gpio_nr = gpio; + gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ;drop
gpio_nrandactive_lowdrivers/media/rc/gpio-ir-tx.c line 169
Quoted 11 lines
drivers/media/rc/gpio-ir-tx.c new file +11
-0+ gpio_ir->carrier =38000 ; + gpio_ir->duty_cycle =50 ; +spin_lock_init (&gpio_ir->lock); + + rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); +if (rc <0 ) +return rc; + + rc =gpio_direction_output (gpio, !gpio_ir->active_low); +if (rc <0 ) +return rc;drop
devm_gpio_requestandgpio_direction_output, that is already handled bydevm_gpiod_get.Quoted 14 lines
drivers/media/rc/gpio-ir-tx.c new file +14
-0+ + rc =devm_rc_register_device (&pdev->dev, rcdev); +if (rc <0 ) +dev_err (&pdev->dev,"failed to register rc device\n" ); + +return rc; +} + +static struct platform_driver gpio_ir_tx_driver = { + .probe = gpio_ir_tx_probe, + .driver = { + .name =DRIVER_NAME , + .of_match_table =of_match_ptr (gpio_ir_tx_of_match), + },
Quoted 8 lines
Quoted 8 lines
drivers/media/rc/gpio-ir-tx.c new file +6
-0+}; +module_platform_driver (gpio_ir_tx_driver); + +MODULE_DESCRIPTION ("GPIO Bit Banging IR Transmitter" ); +MODULE_AUTHOR ("Sean Young <[email protected]>" ); +MODULE_LICENSE ("GPL" );Signature · 1 line
2.9.4
I agree with your comments.
Quoted 103 lines
so long,
Hias
---drivers/media/rc/gpio-ir-tx.c +13
-28@@ -13,11 +13,10 @@#include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <media/rc-core.h> @@ -25,8 +24,7 @@#define DEVICE_NAME "GPIO Bit Banging IR Transmitter"struct gpio_ir { -int gpio_nr; -bool active_low; +struct gpio_desc *gpio;unsigned int carrier;unsigned int duty_cycle;/* we need a spinlock to hold the cpu while transmitting */ @@ -101,14 +99,12 @@ static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,ktime_t last =ktime_add_us (edge, txbuf[i]);while (ktime_get () < last) { -gpio_set_value (gpio_ir->gpio_nr, - gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,1 ); edge += pulse; delta = edge -ktime_get ();if (delta >0 )ndelay (delta); -gpio_set_value (gpio_ir->gpio_nr, - !gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,0 ); edge += space; delta = edge -ktime_get ();if (delta >0 )@@ -128,16 +124,7 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) {struct gpio_ir *gpio_ir;struct rc_dev *rcdev; -enum of_gpio_flags flags; -int rc, gpio; - - gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); -if (gpio <0 ) { -if (gpio != -EPROBE_DEFER ) -dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , - gpio); -return -EINVAL ; - } +int rc; gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL );if (!gpio_ir)@@ -147,6 +134,14 @@ static int gpio_ir_tx_probe(struct platform_device *pdev)if (!rcdev)return -ENOMEM ; + gpio_ir->gpio =devm_gpiod_get (&pdev->dev,NULL ,GPIOD_OUT_LOW ); +if (IS_ERR (gpio_ir->gpio)) { +if (PTR_ERR (gpio_ir->gpio) != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio (%ld)\n" , +PTR_ERR (gpio_ir->gpio)); +return PTR_ERR (gpio_ir->gpio); + } + rcdev->priv = gpio_ir; rcdev->driver_name =DRIVER_NAME ; rcdev->device_name =DEVICE_NAME ;@@ -154,20 +149,10 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; - gpio_ir->gpio_nr = gpio; - gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ; gpio_ir->carrier =38000 ; gpio_ir->duty_cycle =50 ;spin_lock_init (&gpio_ir->lock); - rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); -if (rc <0 ) -return rc; - - rc =gpio_direction_output (gpio, !gpio_ir->active_low); -if (rc <0 ) -return rc; - rc =devm_rc_register_device (&pdev->dev, rcdev);if (rc <0 )dev_err (&pdev->dev,"failed to register rc device\n" );
PATCH 1/1 rc: gpio-ir-tx: switch to gpiod, fix inverted polarity
Manual handling of gpio output polarity was inverted. Switch to using gpiod, this allows us to simplify the code, delegate polarity handling to gpiod and remove the buggy local polarity handling code.
---
This patch is against [PATCH v2 3/6] [media] rc: gpio-ir-tx:
add new driver.
Feel free to squash these two patches into one for v3.
so long,
Hias
drivers/media/rc/gpio-ir-tx.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-)
drivers/media/rc/gpio-ir-tx.c +13 -28
@@ -13,11 +13,10 @@#include <linux/kernel.h> #include <linux/module.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <media/rc-core.h>
@@ -25,8 +24,7 @@#define DEVICE_NAME "GPIO Bit Banging IR Transmitter"struct gpio_ir { -int gpio_nr; -bool active_low; +struct gpio_desc *gpio;unsigned int carrier;unsigned int duty_cycle;/* we need a spinlock to hold the cpu while transmitting */
@@ -101,14 +99,12 @@ static int gpio_ir_tx(struct rc_dev *dev, unsigned int *txbuf,ktime_t last =ktime_add_us (edge, txbuf[i]);while (ktime_get () < last) { -gpio_set_value (gpio_ir->gpio_nr, - gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,1 ); edge += pulse; delta = edge -ktime_get ();if (delta >0 )ndelay (delta); -gpio_set_value (gpio_ir->gpio_nr, - !gpio_ir->active_low); +gpiod_set_value (gpio_ir->gpio,0 ); edge += space; delta = edge -ktime_get ();if (delta >0 )
@@ -128,16 +124,7 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) {struct gpio_ir *gpio_ir;struct rc_dev *rcdev; -enum of_gpio_flags flags; -int rc, gpio; - - gpio =of_get_gpio_flags (pdev->dev.of_node,0 , &flags); -if (gpio <0 ) { -if (gpio != -EPROBE_DEFER ) -dev_err (&pdev->dev,"Failed to get gpio flags (%d)\n" , - gpio); -return -EINVAL ; - } +int rc; gpio_ir =devm_kmalloc (&pdev->dev,sizeof (*gpio_ir),GFP_KERNEL );if (!gpio_ir)
@@ -147,6 +134,14 @@ static int gpio_ir_tx_probe(struct platform_device *pdev)if (!rcdev)return -ENOMEM ; + gpio_ir->gpio =devm_gpiod_get (&pdev->dev,NULL ,GPIOD_OUT_LOW ); +if (IS_ERR (gpio_ir->gpio)) { +if (PTR_ERR (gpio_ir->gpio) != -EPROBE_DEFER ) +dev_err (&pdev->dev,"Failed to get gpio (%ld)\n" , +PTR_ERR (gpio_ir->gpio)); +return PTR_ERR (gpio_ir->gpio); + } + rcdev->priv = gpio_ir; rcdev->driver_name =DRIVER_NAME ; rcdev->device_name =DEVICE_NAME ;
@@ -154,20 +149,10 @@ static int gpio_ir_tx_probe(struct platform_device *pdev) rcdev->s_tx_duty_cycle = gpio_ir_tx_set_duty_cycle; rcdev->s_tx_carrier = gpio_ir_tx_set_carrier; - gpio_ir->gpio_nr = gpio; - gpio_ir->active_low = (flags &OF_GPIO_ACTIVE_LOW ) !=0 ; gpio_ir->carrier =38000 ; gpio_ir->duty_cycle =50 ;spin_lock_init (&gpio_ir->lock); - rc =devm_gpio_request (&pdev->dev, gpio,"gpio-ir-tx" ); -if (rc <0 ) -return rc; - - rc =gpio_direction_output (gpio, !gpio_ir->active_low); -if (rc <0 ) -return rc; - rc =devm_rc_register_device (&pdev->dev, rcdev);if (rc <0 )dev_err (&pdev->dev,"failed to register rc device\n" );
Signature · 1 line
2.11.0
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v2 5/6 dt-bindings: gpio-ir-tx: add support for GPIO IR Transmitter
Document the device tree bindings for the GPIO Bit Banging IR Transmitter.
--- Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt new file +11 -0
@@ -0,0 +1,11 @@ +Device tree bindings for IR LED connected through gpio pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "gpio-ir-tx". + +Example: + irled@0 { + compatible = "gpio-ir-tx"; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + };
Signature · 6 lines
2.9.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Rob Herring
maintainerRe: [PATCH v2 5/6] [media] dt-bindings: gpio-ir-tx: add support for GPIO IR Transmitter
Quoted 15 lines · Sean Young
Document the device tree bindings for the GPIO Bit Banging IR Transmitter.
Signed-off-by Sean Young <[email protected]>--- Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txtDocumentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt new file +0
-0
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt line 5
Quoted 5 lines
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt new file +5
-0@@ -0,0 +1,11 @@ +Device tree bindings for IR LED connected through gpio pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "gpio-ir-tx".
As I mentioned in the prior version, missing the "gpios" property.
Quoted 13 lines
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt new file +6
-0+ +Example: + irled@0 { + compatible = "gpio-ir-tx"; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + };Signature · 6 lines
2.9.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 5/6] [media] dt-bindings: gpio-ir-tx: add support for GPIO IR Transmitter
Quoted 10 lines · Rob Herring
Quoted 9 lines · Sean Young
Document the device tree bindings for the GPIO Bit Banging IR Transmitter.
Signed-off-by Sean Young <[email protected]>--- Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt
Quoted 13 lines
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt line 5
Quoted 11 lines
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt new file +5
-0@@ -0,0 +1,11 @@ +Device tree bindings for IR LED connected through gpio pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "gpio-ir-tx".As I mentioned in the prior version, missing the "gpios" property.
Absolutely right. I hadn't gotten round to sending out a new version yet, I'll do that soon.
Thanks,
Sean
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20170710151016.5iaokchdejxozrte-3XSxi2G4b3iXFJAUJl40Xg@public.gmane.org
PATCH v3 1/1 dt-bindings: gpio-ir-tx: add support for GPIO IR Transmitter
Document the device tree bindings for the GPIO Bit Banging IR Transmitter.
--- .../devicetree/bindings/leds/irled/gpio-ir-tx.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt
Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt new file +14 -0
@@ -0,0 +1,14 @@ +Device tree bindings for IR LED connected through gpio pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "gpio-ir-tx". + - gpios : Should specify the IR LED GPIO, see "gpios property" in + Documentation/devicetree/bindings/gpio/gpio.txt. Active low LEDs + should be indicated using flags in the GPIO specifier. + +Example: + irled@0 { + compatible = "gpio-ir-tx"; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + };
Signature · 6 lines
2.9.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3] [media] dt-bindings: gpio-ir-tx: add support for GPIO IR Transmitter
Quoted 8 lines · Sean Young
Document the device tree bindings for the GPIO Bit Banging IR Transmitter.
Signed-off-by Sean Young <[email protected]>--- .../devicetree/bindings/leds/irled/gpio-ir-tx.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.txt
A message that is not in the archive (sent off-list or not yet received): 580c648de65344e9316ff153ba316efd4d527f12.1499419624.git.sean-hENCXIMQXOg@public.gmane.org
PATCH v2 6/6 dt-bindings: pwm-ir-tx: Add support for PWM IR Transmitter
Document the device tree bindings for the PWM IR Transmitter.
--- Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.txt
Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.txt new file +13 -0
@@ -0,0 +1,13 @@ +Device tree bindings for IR LED connected through pwm pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "pwm-ir-tx". + - pwms : PWM property to point to the PWM device (phandle)/port (id) + and to specify the period time to be used: <&phandle id period_ns>; + +Example: + irled { + compatible = "pwm-ir-tx"; + pwms = <&pwm0 0 10000000>; + };
Signature · 6 lines
2.9.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): e18cec2d3f66cd59d8683cb07fc59e3a2086cf6e.1499419624.git.sean-hENCXIMQXOg@public.gmane.org
Rob Herring
Acked-byRe: [PATCH v2 6/6] [media] dt-bindings: pwm-ir-tx: Add support for PWM IR Transmitter
Quoted 7 lines · Sean Young
Document the device tree bindings for the PWM IR Transmitter.
Signed-off-by Sean Young <[email protected]>--- Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.txt
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Sean Young
maintainerPATCH v2 4/6 rc: pwm-ir-tx: add new driver
In reply to Sean YoungThis is new driver which uses pwm, so it is more power-efficient than the bit banging gpio-ir-tx driver.
--- MAINTAINERS | 6 ++ drivers/media/rc/Kconfig | 12 ++++ drivers/media/rc/Makefile | 1 + drivers/media/rc/pwm-ir-tx.c | 138 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/media/rc/pwm-ir-tx.c
MAINTAINERS +6 -0
@@ -10449,6 +10449,12 @@ F: Documentation/devicetree/bindings/hwmon/pwm-fan.txt F: Documentation/hwmon/pwm-fan F: drivers/hwmon/pwm-fan.c +PWM IR Transmitter +M: Sean Young <[email protected]> +L: [email protected] +S: Maintained +F: drivers/media/rc/pwm-ir-tx.c + PWM SUBSYSTEM M: Thierry Reding <[email protected]> L: [email protected]
drivers/media/rc/Kconfig +12 -0
@@ -410,6 +410,18 @@ config IR_GPIO_TX To compile this driver as a module, choose M here: the module will be called gpio-ir-tx. +config IR_PWM_TX + tristate "PWM IR transmitter" + depends on RC_CORE + depends on LIRC + depends on PWM + ---help--- + Say Y if you want to use a PWM based IR transmitter. This is + more power efficient than the bit banging gpio driver. + + To compile this driver as a module, choose M here: the module will + be called pwm-ir-tx. + config RC_ST tristate "ST remote control receiver" depends on RC_CORE
drivers/media/rc/Makefile +1 -0
@@ -33,6 +33,7 @@ obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o obj-$(CONFIG_IR_GPIO_TX) += gpio-ir-tx.o +obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o obj-$(CONFIG_IR_IGORPLUGUSB) += igorplugusb.o obj-$(CONFIG_IR_IGUANA) += iguanair.o obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
drivers/media/rc/pwm-ir-tx.c new file +138 -0
138 lines not on this page · raw message
Signature · 1 line
2.9.4
Re: [PATCH v2 4/6] [media] rc: pwm-ir-tx: add new driver
Quoted 11 lines · Sean Young
This is new driver which uses pwm, so it is more power-efficient than the bit banging gpio-ir-tx driver.
Signed-off-by Sean Young <[email protected]>--- MAINTAINERS | 6 ++ drivers/media/rc/Kconfig | 12 ++++ drivers/media/rc/Makefile | 1 + drivers/media/rc/pwm-ir-tx.c | 138 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/media/rc/pwm-ir-tx.c
nothing apparently wrong.
Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Re: [PATCH v2 4/6] [media] rc: pwm-ir-tx: add new driver
In reply to Sean YoungHi Sean,
sorry for double-post, forgot to CC the list and others.
Quoted 4 lines · Sean Young
This is new driver which uses pwm, so it is more power-efficient than the bit banging gpio-ir-tx driver.
Signed-off-by Sean Young <[email protected]>
Tested on RPi2, with downstream RPi kernel 4.13-rc1, using ir-ctl to send RC-5 codes, against another RPi with gpio-ir-recv. Also verified signal polarity and frequency on scope.
so long & thanks a lot,
Hias
Quoted 207 lines
--- MAINTAINERS | 6 ++ drivers/media/rc/Kconfig | 12 ++++ drivers/media/rc/Makefile | 1 + drivers/media/rc/pwm-ir-tx.c | 138 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 drivers/media/rc/pwm-ir-tx.cMAINTAINERS +6
-0@@ -10449,6 +10449,12 @@ F: Documentation/devicetree/bindings/hwmon/pwm-fan.txt F: Documentation/hwmon/pwm-fan F: drivers/hwmon/pwm-fan.c +PWM IR Transmitter +M: Sean Young <[email protected]> +L: [email protected] +S: Maintained +F: drivers/media/rc/pwm-ir-tx.c + PWM SUBSYSTEM M: Thierry Reding <[email protected]> L: [email protected]drivers/media/rc/Kconfig +12
-0@@ -410,6 +410,18 @@ config IR_GPIO_TX To compile this driver as a module, choose M here: the module will be called gpio-ir-tx. +config IR_PWM_TX + tristate "PWM IR transmitter" + depends on RC_CORE + depends on LIRC + depends on PWM + ---help--- + Say Y if you want to use a PWM based IR transmitter. This is + more power efficient than the bit banging gpio driver. + + To compile this driver as a module, choose M here: the module will + be called pwm-ir-tx. + config RC_ST tristate "ST remote control receiver" depends on RC_COREdrivers/media/rc/Makefile +1
-0@@ -33,6 +33,7 @@ obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o obj-$(CONFIG_IR_GPIO_TX) += gpio-ir-tx.o +obj-$(CONFIG_IR_PWM_TX) += pwm-ir-tx.o obj-$(CONFIG_IR_IGORPLUGUSB) += igorplugusb.o obj-$(CONFIG_IR_IGUANA) += iguanair.o obj-$(CONFIG_IR_TTUSBIR) += ttusbir.odrivers/media/rc/pwm-ir-tx.c new file +138
-0@@ -0,0 +1,138 @@ +/* +* Copyright (C) 2017 Sean Young <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pwm.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/rc-core.h> + +#define DRIVER_NAME "pwm-ir-tx" +#define DEVICE_NAME "PWM IR Transmitter" + +struct pwm_ir { +struct pwm_device *pwm; +unsigned int carrier; +unsigned int duty_cycle; +}; + +static const struct of_device_id pwm_ir_of_match[] = { + { .compatible ="pwm-ir-tx" , }, + { }, +}; +MODULE_DEVICE_TABLE (of, pwm_ir_of_match); + +static int pwm_ir_set_duty_cycle (struct rc_dev *dev,u32 duty_cycle) +{ +struct pwm_ir *pwm_ir = dev->priv; + + pwm_ir->duty_cycle = duty_cycle; + +return 0 ; +} + +static int pwm_ir_set_carrier (struct rc_dev *dev,u32 carrier) +{ +struct pwm_ir *pwm_ir = dev->priv; + +if (!carrier) +return -EINVAL ; + + pwm_ir->carrier = carrier; + +return 0 ; +} + +static int pwm_ir_tx (struct rc_dev *dev,unsigned int *txbuf, +unsigned int count) +{ +struct pwm_ir *pwm_ir = dev->priv; +struct pwm_device *pwm = pwm_ir->pwm; +int i, duty, period; +ktime_t edge; +long delta; + + period =DIV_ROUND_CLOSEST (NSEC_PER_SEC , pwm_ir->carrier); + duty =DIV_ROUND_CLOSEST (pwm_ir->duty_cycle * period,100 ); + +pwm_config (pwm, duty, period); + + edge =ktime_get (); + +for (i =0 ; i < count; i++) { +if (i %2 )// space +pwm_disable (pwm); +else +pwm_enable (pwm); + + edge =ktime_add_us (edge, txbuf[i]); + delta =ktime_us_delta (edge,ktime_get ()); +if (delta >0 ) +usleep_range (delta, delta +10 ); + } + +pwm_disable (pwm); + +return count; +} + +static int pwm_ir_probe (struct platform_device *pdev) +{ +struct pwm_ir *pwm_ir; +struct rc_dev *rcdev; +int rc; + + pwm_ir =devm_kmalloc (&pdev->dev,sizeof (*pwm_ir),GFP_KERNEL ); +if (!pwm_ir) +return -ENOMEM ; + + pwm_ir->pwm =devm_pwm_get (&pdev->dev,NULL ); +if (IS_ERR (pwm_ir->pwm)) +return PTR_ERR (pwm_ir->pwm); + + pwm_ir->carrier =38000 ; + pwm_ir->duty_cycle =50 ; + + rcdev =devm_rc_allocate_device (&pdev->dev,RC_DRIVER_IR_RAW_TX ); +if (!rcdev) +return -ENOMEM ; + + rcdev->priv = pwm_ir; + rcdev->driver_name =DRIVER_NAME ; + rcdev->device_name =DEVICE_NAME ; + rcdev->tx_ir = pwm_ir_tx; + rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle; + rcdev->s_tx_carrier = pwm_ir_set_carrier; + + rc =devm_rc_register_device (&pdev->dev, rcdev); +if (rc <0 ) +dev_err (&pdev->dev,"failed to register rc device\n" ); + +return rc; +} + +static struct platform_driver pwm_ir_driver = { + .probe = pwm_ir_probe, + .driver = { + .name =DRIVER_NAME , + .of_match_table =of_match_ptr (pwm_ir_of_match), + }, +}; +module_platform_driver (pwm_ir_driver); + +MODULE_DESCRIPTION ("PWM IR Transmitter" ); +MODULE_AUTHOR ("Sean Young <[email protected]>" ); +MODULE_LICENSE ("GPL" );Signature · 1 line
2.9.4