Play Transfer Far SC60 Android Development Board ------ (4) USB and OTG switch

On SC60, we intend to realize the soft switch between usb device and otg, that is, realize the switch between usb device and otg through software settings.
A GPIO can be designed on the schematic diagram to control the switching of the USB ID and the data line. In terms of VBUS power supply, otg uses external power supply, so you don't need to consider it; when used as a device, vbus can be used to detect insertion.
The reference schematic diagram is as follows: The
Insert picture description here
figure uses GPIO_96 as the pin to control the switch. When it outputs 0, the USB_ID pin is high and the s pin is high. The USB switch selects HSD1: USB_DP_EXT and USB_DM_EXT, and the module is used as a device;
GPIO_96 When outputting 1, the USB_ID pin is low, and the USB switch selects HSD2: USB_DP_COM and USB_DM_COM. At this time, the module acts as the host and connects the OTG device externally.

Reference driver:

#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");

In this way, the node can be used to control the usb state.
Read otg status:
cat /sys/bus/platform/devices/sc60_otg_control/sc60_gpio
set otg status:
echo 1> /sys/bus/platform/devices/sc60_otg_control/sc60_gpio
set USB status:
echo 0> /sys/bus/platform /devices/sc60_otg_control/sc60_gpio

Guess you like

Origin blog.csdn.net/cornerstone1/article/details/113136765