玩转移远SC60 Android开发板------(4)USB和otg切换

在SC60上打算实现usb device和otg的软切换,即通过软件设置实现usb device和otg的切换。
原理图上可以设计一个GPIO来控制USB ID和数据线的切换。VBUS的供电方面,otg使用外供电,可以不用考虑;作device时vbus用来检测插入即可。
参考原理图如下:
在这里插入图片描述
图中使用GPIO_96作为控制切换的管脚,它输出0时,USB_ID脚为高,s脚为高,usb切换开关选择的是HSD1:USB_DP_EXT和USB_DM_EXT,此时模块作为device;
GPIO_96输出1时,USB_ID脚为低,usb切换开关选择的是HSD2:USB_DP_COM和USB_DM_COM,此时模块作为host,外部连接otg设备。

参考驱动:

#include <linux/device.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h> 
#include <linux/module.h>
#include <linux/semaphore.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/gpio.h>

#define SC60_GPIO_SET_MAJOR    198
#define SC60_DO1            0x1
#define SC60_DO2            0x2


u32 gpio_num[]={
  96,
};


struct SC60_gpio_dev{
	struct cdev cdev;
};

struct SC60_gpio_dev *SC60_gpio_devp;

static int SC60_gpio_major = SC60_GPIO_SET_MAJOR;


int SC60_gpio_open(struct inode *inode, struct file *filp)
{
	//printk(KERN_ERR "###sc60### SC60_gpio open in\n");
	filp->private_data = SC60_gpio_devp;

	return 0;
}

int SC60_gpio_release(struct inode *inode, struct file *filp)
{
	//printk(KERN_ERR "###sc60### SC60_gpio release in\n");
	return 0;
}

static ssize_t SC60_gpio_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
	__attribute__((__unused__)) struct SC60_gpio_dev *dev = filp->private_data;
	//copy_to_user
	//printk(KERN_ERR "###sc60### SC60_gpio read in\n");
	
	return 0;
}

static ssize_t SC60_gpio_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
	__attribute__((__unused__)) struct SC60_gpio_dev *dev = filp->private_data;
	//copy_from_user
	//printk(KERN_ERR "###sc60### SC60_gpio write in\n");

	return -1;
}

static loff_t SC60_gpio_llseek(struct file *filp, loff_t offset, int orig)
{
	//printk(KERN_ERR "###sc60### SC60_gpio llseek in\n");
	//filp->f_pos
	switch(orig){
	case 0:
		break;
	case 1:
		break;
	default:
		break;
	}

	return 0;
}

static long SC60_gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	__attribute__((__unused__)) struct SC60_gpio_dev *dev = filp->private_data;
	//printk(KERN_ERR "###sc60### SC60_gpio ioctl in\n");
	
	switch(cmd){
	case SC60_DO1:
		break;
	case SC60_DO2:
	default:
		break;
	}

	return 0;
}

static const struct file_operations SC60_gpio_fops = {
	.owner = THIS_MODULE,
	.llseek = SC60_gpio_llseek,
	.read = SC60_gpio_read,
	.write = SC60_gpio_write,
	.unlocked_ioctl = SC60_gpio_ioctl,
	.open = SC60_gpio_open,
	.release = SC60_gpio_release,
};

struct class *SC60_gpio_class;

static void SC60_gpio_setup_cdev(struct SC60_gpio_dev *dev, int index)
{
	int err, devno;
	devno = MKDEV(SC60_gpio_major, index);
	printk(KERN_ERR "###sc60### SC60_gpio SC60_gpio_setup_cdev\n");

	cdev_init(&dev->cdev, &SC60_gpio_fops);
	dev->cdev.owner = THIS_MODULE;
	err = cdev_add(&dev->cdev, devno, 1);
	if(err)
	{
		printk(KERN_ERR "###sc60### %d add SC60_gpio %d\n", err, index);
	}

	SC60_gpio_class = class_create(THIS_MODULE, "sc60_otg_set");
	//stone comment
	//这里的名字是/dev/下面的名字
	// create device in /dev/sc60_otg_set
	//实际在/sys/class/sc60_otg_set
	// but the real device is /sys/bus/platform/devices/SC60_otg_control
	device_create(SC60_gpio_class, NULL, devno, NULL, "sc60_otg_set");
}

static bool gpio_flag = 0;

static ssize_t SC60_gpio_get(struct device *dev, struct device_attribute *attr, char *buf)
{
	int ret = 0;

	if(gpio_flag)
		//print chars to buf
		//ret = snprintf(buf, PAGE_SIZE, "%d\n", SC60_adc1_to_vol());
		ret = snprintf(buf, PAGE_SIZE, "--otg set--\n");
	else
		ret = snprintf(buf, PAGE_SIZE, "--host set--\n");

	return ret;
}

static ssize_t SC60_gpio_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	int stat;

	//char to int
	stat = buf[0] - '0';

	printk(KERN_ERR "set gpio status :%d \n", stat);
	
	gpio_free(gpio_num[0]);
	gpio_request(gpio_num[0], NULL);
	if(stat == 0)
	{
		gpio_direction_output(gpio_num[0], 0);
		gpio_flag = stat;
	}
	if(stat == 1)
	{
		gpio_direction_output(gpio_num[0], 1);
		gpio_flag = stat;
	}
		
	return count;
}
static DEVICE_ATTR(SC60_gpio, 0664, SC60_gpio_get, SC60_gpio_set);


static int __init SC60_gpio_probe(struct platform_device *pdev)
{
	int result;
	
	dev_t devno = MKDEV(SC60_gpio_major, 0);
	printk(KERN_ERR "###sc60### SC60_gpio_probe in\n");

	if(SC60_gpio_major)
	{
		//这里是分配设备号
		//cat proc/devices 看到198 SC60_gpio_control
		result = register_chrdev_region(devno, 1, "SC60_gpio_control");
	}
	else
	{
		result = alloc_chrdev_region(&devno, 0, 1, "SC60_gpio_control");
		SC60_gpio_major = MAJOR(devno);
	}
	if(result < 0)
	{
		return result;
	}

	SC60_gpio_devp = kmalloc(sizeof(struct SC60_gpio_dev), GFP_KERNEL);
	
	if(!SC60_gpio_devp){
		result = -ENOMEM;
		goto fail_malloc;
	}
	memset(SC60_gpio_devp, 0, sizeof(struct SC60_gpio_dev));

	SC60_gpio_setup_cdev(SC60_gpio_devp, 0);

	
	//这里创建的节点是在/sys/bus/platform/devices/SC60_otg_control下
	//SC60_otg_control这个名字是由SC60_gpio_device和SC60_gpio_device_driver的名字决定的
	device_create_file(&pdev->dev, &dev_attr_sc60_gpio);

	printk(KERN_ERR "###sc60### SC60_gpio_probe out\n");

	return 0;

fail_malloc:
	unregister_chrdev_region(devno, 1);
	
	return result;
}

static int __exit SC60_gpio_remove(struct platform_device *pdev)
{
	cdev_del(&SC60_gpio_devp->cdev);
	kfree(SC60_gpio_devp);

	device_destroy(SC60_gpio_class, MKDEV(SC60_gpio_major, 0));
	class_destroy(SC60_gpio_class);

	unregister_chrdev_region(MKDEV(SC60_gpio_major, 0), 1);
	return 0;
}

static struct platform_driver SC60_gpio_device_driver = {
        .probe   = SC60_gpio_probe,
        .remove  = SC60_gpio_remove,

        .driver  = {
                .name = "SC60_otg_control",
                .owner = THIS_MODULE,
        },
};

static struct platform_device SC60_gpio_device = {
        .name    = "SC60_otg_control",
        .id      = -1,
};

static int __init SC60_gpio_init(void)
{
	platform_device_register(&SC60_gpio_device);
	return platform_driver_register(&SC60_gpio_device_driver);
}

static void __exit SC60_codec_exit(void)
{
	platform_driver_unregister(&SC60_gpio_device_driver);
	platform_device_unregister(&SC60_gpio_device);
}

module_init(SC60_gpio_init);
module_exit(SC60_codec_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("stone");
MODULE_DESCRIPTION("stone for SC60 gpio-set CTRL");

这样就可以使用节点控制usb状态了。
读取otg状态:
cat /sys/bus/platform/devices/sc60_otg_control/sc60_gpio
设置otg状态:
echo 1 > /sys/bus/platform/devices/sc60_otg_control/sc60_gpio
设置USB状态:
echo 0 > /sys/bus/platform/devices/sc60_otg_control/sc60_gpio

猜你喜欢

转载自blog.csdn.net/cornerstone1/article/details/113136765
今日推荐