Android下的遥控器DIY

https://blog.csdn.net/mike8825/article/details/80955992中,介绍了几种红外方案,这里拿spi的方式来diy一个遥控器。

如果内核版本是v4.14,直接编译kernel4.14/drivers/media/rc/ir-spi.c文件,调试下,应该就可以用了。这里稍微改造了ir-spi.c,更加容易移植。

dts参考配置

记的打开平台的dma模式(在https://blog.csdn.net/mike8825/article/details/80955992已说明原因)

&spi1 {
    status = "okay";
	sprd,dma-mode = <1>;
	sprd,spi-mode = <3>;
		irled@0 {
			compatible = "ir-spi-led";
			reg = <0x0>;
			spi-max-frequency = <5000000>;
			duty-cycle = /bits/ 8 <60>;
	}; 
};

如果mos管是低电平导通,加上led-active-low;

ir-spi.c 

// SPDX-License-Identifier: GPL-2.0
// SPI driven IR LED device driver
//
// Copyright (c) 2016 Samsung Electronics Co., Ltd.
// Copyright (c) Andi Shyti <andi@etezian.org>
 
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
//#include <media/rc-core.h>
 
#define IR_SPI_DRIVER_NAME		"ir-spi"
#define IR_SPI_DEFAULT_FREQUENCY	38000
#define IR_SPI_MAX_BUFSIZE		4096*4
#define	TX_IR				_IOW(0xf5, 0, int)
#define	SET_TX_CARRIER			_IOW(0xf5, 1, int)
 
struct ir_spi_data {
	u32 freq;
	bool negated;
 
	u16 tx_buf[IR_SPI_MAX_BUFSIZE];
	u16 pulse;
	u16 space;
 
	struct spi_device *spi;
	struct regulator *regulator;
};
 
struct ir_spi_data idata;
 
static int ir_spi_open(struct inode *inode, struct file *file)
{
	return 0;
}
 
static ssize_t ir_spi_tx(struct file *file, const char __user * user_buf,
			 size_t count, loff_t * ppos)
{
	int i;
	int ret;
	unsigned int len = 0;
	int *buffer;
	struct spi_transfer xfer;
	pr_info("ir_spi_tx start\n");
	buffer= memdup_user(user_buf, count);
	count /= sizeof(int);
 
	/* convert the pulse/space signal to raw binary signal */
	for (i = 0; i < count; i++) {
		unsigned int periods;
		int j;
		u16 val;
		periods = DIV_ROUND_CLOSEST(buffer[i] * idata.freq, 1000000);
		pr_debug("i=%d periods=%d\n",i,periods);
		if (len>= IR_SPI_MAX_BUFSIZE){
			pr_info("len=%d\n",len);
			return -EINVAL;
		}
 
		/*
		 * the first value in buffer is a pulse, so that 0, 2, 4, ...
		 * contain a pulse duration. On the contrary, 1, 3, 5, ...
		 * contain a space duration.
		 */
		val = (i % 2) ? idata.space : idata.pulse;
		for (j = 0; j < periods; j++)
			idata.tx_buf[len++] = val;
	}
 
	memset(&xfer, 0, sizeof(xfer));
	
	xfer.speed_hz = idata.freq * 16;
	xfer.len = len * sizeof(*idata.tx_buf);
	xfer.tx_buf = idata.tx_buf;
	xfer.bits_per_word = 16;

	ret = regulator_enable(idata.regulator);
	if (ret)
		return ret;
	ret = spi_sync_transfer(idata.spi, &xfer, 1);
	if (ret)
		dev_err(&idata.spi->dev, "unable to deliver the signal\n");
	regulator_disable(idata.regulator);
	kfree(buffer);
	pr_info("ir_spi_tx stop\n");
	return ret ? ret : count*sizeof(int);
}
 
static long ir_spi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int ret;
	switch (cmd) {
	case SET_TX_CARRIER:
		if (get_user(idata.freq,(unsigned int __user *)arg)){
			return -EFAULT;
		}
		idata.spi->max_speed_hz = idata.freq*16;
		idata.spi->bits_per_word = 16;
		ret = spi_setup(idata.spi);
		if(ret<0){
			dev_err(&idata.spi->dev, "set up spi speed fail\n");
			return ret;
		}
		break;
	default:
		return -ENOIOCTLCMD;
	}
	return 0;
}
 
static int ir_spi_set_duty_cycle(u32 duty_cycle)
{
	int bits = (duty_cycle * 15) / 100;
 
	idata.pulse = GENMASK(bits, 0);
 
	if (idata.negated) {
		idata.pulse = ~idata.pulse;
		idata.space = 0xffff;
	} else {
		idata.space = 0;
	}
 
	return 0;
}
 
static int ir_spi_release(struct inode *node, struct file *filp)
{
	return 0;
}
 
static struct file_operations ir_spi_fops = {
	.owner = THIS_MODULE,
	.open = ir_spi_open,
	.unlocked_ioctl = ir_spi_ioctl,
	.write = ir_spi_tx,
	.release = ir_spi_release,
};
 
static struct miscdevice ir_spi_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = IR_SPI_DRIVER_NAME,
	.fops = &ir_spi_fops,
};
 
static int ir_spi_probe(struct spi_device *spi)
{
	int ret;
	u8 dc;
	idata.spi= spi;
	idata.regulator = devm_regulator_get(&spi->dev, "irda_regulator");
	if (IS_ERR(idata.regulator))
		pr_err("could no found irda regu_regulator %ld",
		       PTR_ERR(idata.regulator));
 
	idata.negated =
	    of_property_read_bool(spi->dev.of_node, "led-active-low");
	ret = of_property_read_u8(spi->dev.of_node, "duty-cycle", &dc);
	if (ret)
		dc = 50;
	ir_spi_set_duty_cycle(dc);
 
	idata.freq = IR_SPI_DEFAULT_FREQUENCY;
	ret = misc_register(&ir_spi_dev);
	return 0;
}
 
static int ir_spi_remove(struct spi_device *spi)
{
	return 0;
}
 
static const struct of_device_id ir_spi_of_match[] = {
	{.compatible = "ir-spi-led"},
	{},
};
 
static struct spi_driver ir_spi_driver = {
	.probe = ir_spi_probe,
	.remove = ir_spi_remove,
	.driver = {
		   .name = IR_SPI_DRIVER_NAME,
		   .of_match_table = ir_spi_of_match,
		   },
};
 
module_spi_driver(ir_spi_driver);
 
MODULE_AUTHOR("Andi Shyti <andi@etezian.org>");
MODULE_DESCRIPTION("SPI IR LED");
MODULE_LICENSE("GPL v2");

hardware/libhardware/modules/consumerir/consumerir.c 

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#define LOG_TAG "ConsumerIrHal"

#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>

#include <log/log.h>

#include <hardware/consumerir.h>
#include <hardware/hardware.h>
#define	TX_IR				_IOW(0xf5, 0, int)
#define	SET_TX_CARRIER			_IOW(0xf5, 1, int)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static const consumerir_freq_range_t consumerir_freqs[] = {
	{.min = 30000,.max = 30000},
	{.min = 33000,.max = 33000},
	{.min = 36000,.max = 36000},
	{.min = 38000,.max = 38000},
	{.min = 40000,.max = 40000},
	{.min = 56000,.max = 56000},
};

static int consumerir_transmit(struct consumerir_device *dev __unused,
			       int carrier_freq, const int pattern[],
			       int pattern_len)
{
	int fd;
	int ret;
	int length;
	int freq;
	fd = open("/dev/ir-spi", O_RDWR);
	if (fd < 0) {
		ALOGE("open /dev/ir-spi error");
		return -1;
	}
	freq = carrier_freq;
	ret = ioctl(fd, SET_TX_CARRIER, &freq);
	if (ret < 0)
		ALOGE("set ir freq fail\n");
	length = pattern_len * sizeof(int);
	ret = write(fd, pattern, length);
	if (ret != length) {
		ALOGE("consumerir_transmit fail ret=%d length=%d\n", ret,
		      length);
	} else {
		ALOGE("consumerir_transmit ok\n");
	}

	return 0;
}

static int consumerir_get_num_carrier_freqs(struct consumerir_device *dev
					    __unused)
{
	return ARRAY_SIZE(consumerir_freqs);
}

static int consumerir_get_carrier_freqs(struct consumerir_device *dev __unused,
					size_t len,
					consumerir_freq_range_t * ranges)
{
	size_t to_copy = ARRAY_SIZE(consumerir_freqs);

	to_copy = len < to_copy ? len : to_copy;
	memcpy(ranges, consumerir_freqs,
	       to_copy * sizeof(consumerir_freq_range_t));
	return to_copy;
}

static int consumerir_close(hw_device_t * dev)
{
	free(dev);
	return 0;
}

/*
 * Generic device handling
 */
static int consumerir_open(const hw_module_t * module, const char *name,
			   hw_device_t ** device)
{
	if (strcmp(name, CONSUMERIR_TRANSMITTER) != 0) {
		return -EINVAL;
	}
	if (device == NULL) {
		ALOGE("NULL device on open");
		return -EINVAL;
	}

	consumerir_device_t *dev = malloc(sizeof(consumerir_device_t));
	memset(dev, 0, sizeof(consumerir_device_t));

	dev->common.tag = HARDWARE_DEVICE_TAG;
	dev->common.version = 0;
	dev->common.module = (struct hw_module_t *)module;
	dev->common.close = consumerir_close;

	dev->transmit = consumerir_transmit;
	dev->get_num_carrier_freqs = consumerir_get_num_carrier_freqs;
	dev->get_carrier_freqs = consumerir_get_carrier_freqs;

	*device = (hw_device_t *) dev;
	return 0;
}

static struct hw_module_methods_t consumerir_module_methods = {
	.open = consumerir_open,
};

consumerir_module_t HAL_MODULE_INFO_SYM = {
	.common = {
		   .tag = HARDWARE_MODULE_TAG,
		   .module_api_version = CONSUMERIR_MODULE_API_VERSION_1_0,
		   .hal_api_version = HARDWARE_HAL_API_VERSION,
		   .id = CONSUMERIR_HARDWARE_MODULE_ID,
		   .name = "Demo IR HAL",
		   .author = "The Android Open Source Project",
		   .methods = &consumerir_module_methods,
		   },
};

其他的修改见 https://blog.csdn.net/mike8825/article/details/79670891,不再描述。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值