linux SPI PGA2311 Driver

公众号

欢迎扫码关注本人微信公众号:公众号上分享更多嵌入式知识和资料,分享个人学习嵌入式的心得体会。欢迎大家一起来玩呀。
在这里插入图片描述

#include <linux/init.h>                        
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>

#include <linux/delay.h>
#include <linux/err.h>

#include <linux/spi/spi.h>
#include <linux/timer.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>

#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/platform_data/spi-rockchip.h>

#include <linux/delay.h>

#include <dt-bindings/gpio/gpio.h>

#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#endif


#define	pga2311_spi_speed 5000000

struct pga2311_data_t{
    struct spi_device *spi;
    int    gpio_mute;
    int    gpio_mute_is_valid;
    int    gpio_mute_output;
    int    gpio_zce;           //zero crossing enable pin
    int    gpio_zce_is_valid;
    int    gpio_zce_output;
    
    uint8_t right_volume;
    uint8_t left_volume;
}; 

static DEFINE_MUTEX(pga2311_global_lock);
static struct pga2311_data_t *p_pga2311_data = NULL;


/*
* This function write wk2xxx of Global register:
*/
static int pga2311_write_global_reg(struct spi_device *spi,uint8_t right_volume,uint8_t left_volume) {
     struct spi_message msg;
     uint8_t volume[2];
     int status;
     struct spi_transfer index_xfer = {
         .len            = 2,
         .speed_hz	     = pga2311_spi_speed,
     };
     
     mutex_lock(&pga2311_global_lock);
     spi_message_init(&msg);
     /* register index */
     volume[0]         = right_volume;
     volume[1]         = left_volume;
     index_xfer.tx_buf = volume;
     spi_message_add_tail(&index_xfer, &msg);
     status = spi_sync(spi, &msg);
     mutex_unlock(&pga2311_global_lock);
     
     if (status) {
        printk(KERN_ERR "%s!!status=%d!---\n", __func__,status);
     }
     return status;
}


static int pga2311_read_global_reg(struct spi_device *spi,uint8_t *right_volume,uint8_t *left_volume) {    
    struct spi_message msg;
    uint8_t buf_rdat[2];
    int status;
    struct spi_transfer index_xfer = {
            .len            = 2,
            .speed_hz	= pga2311_spi_speed,
    };
    
    mutex_lock(&pga2311_global_lock);
    status =0;
    spi_message_init(&msg);
    index_xfer.rx_buf =(void *) buf_rdat;
    spi_message_add_tail(&index_xfer, &msg);
    status = spi_sync(spi, &msg);
    mutex_unlock(&pga2311_global_lock);
    
    if (status) {
        printk(KERN_ERR "%s!!status=%d!---\n", __func__,status);
        return status;
    }
    
    *right_volume = buf_rdat[0];
    *left_volume  = buf_rdat[1];
    return 0;
}


static ssize_t pga2311_mute_store(struct device *dev, struct device_attribute *attr,
              const char *buf, size_t count) {
    struct pga2311_data_t *pdata = p_pga2311_data;            
    printk(KERN_ERR "pga2311_mute_store %s \n",buf);

    if (buf[0] == '0') {
        pdata->gpio_mute_output = 0;
        gpio_direction_output(pdata->gpio_mute, pdata->gpio_mute_output);
    }else if (buf[0] == '1') {
        pdata->gpio_mute_output = 1;
        gpio_direction_output(pdata->gpio_mute, pdata->gpio_mute_output);
    }    

    printk(KERN_ERR "gpio_mute_output %d \n",pdata->gpio_mute_output);   
    return count;
}

static ssize_t pga2311_zce_store(struct device *dev, struct device_attribute *attr,
            const char *buf, size_t count) {
    struct pga2311_data_t *pdata = p_pga2311_data;        
    printk(KERN_ERR "pga2311_zce_store %s \n",buf);

    if (buf[0] == '0') {
        pdata->gpio_zce_output = 0;
        gpio_direction_output(pdata->gpio_zce, pdata->gpio_zce_output);
    }else if (buf[0] == '1') {
        pdata->gpio_zce_output = 1;
        gpio_direction_output(pdata->gpio_zce, pdata->gpio_zce_output);
    }
    
    printk(KERN_ERR "gpio_zce_output %d \n",pdata->gpio_zce_output);   
    return count;
}

static ssize_t pga2311_set_right_volume_store(struct device *dev, struct device_attribute *attr,
          const char *buf, size_t count) {
    struct pga2311_data_t *pdata = p_pga2311_data;
    int num;
    
    printk(KERN_ERR "pga2311_set_right_volume_store %s \n",buf);
    num = simple_strtol(buf, NULL, 0);
    if ( !(num >= 0 && num <= 255))
       return count;
       
    pdata->right_volume = num;   
    pga2311_write_global_reg(pdata->spi,pdata->right_volume,pdata->left_volume); 
    return count;
}

static ssize_t pga2311_set_left_volume_store(struct device *dev, struct device_attribute *attr,
        const char *buf, size_t count) {
    struct pga2311_data_t *pdata = p_pga2311_data;
    int num;
    
    printk(KERN_ERR "pga2311_set_left_volume_store %s \n",buf);
    num = simple_strtol(buf, NULL, 0);
    if ( !(num >= 0 && num <= 255))
       return count;
       
    pdata->left_volume = num;
    pga2311_write_global_reg(pdata->spi,pdata->right_volume,pdata->left_volume);
    return count;
}

static ssize_t pga2311_set_right_volume_show(struct device *dev, struct device_attribute *attr,
                                              char *buf) {
    uint8_t right_volume = 0;
    uint8_t left_volume  = 0;                                           
    struct pga2311_data_t *pdata = p_pga2311_data;
        
    pga2311_read_global_reg(pdata->spi,&right_volume,&left_volume);
    pga2311_write_global_reg(pdata->spi,pdata->right_volume,pdata->left_volume);
    return snprintf(buf, PAGE_SIZE, "%d\n",
			right_volume);
}


static ssize_t pga2311_set_left_volume_show(struct device *dev, struct device_attribute *attr,
                                             char *buf) {      
    uint8_t right_volume = 0;
    uint8_t left_volume  = 0;                                           
    struct pga2311_data_t *pdata = p_pga2311_data;
        
    pga2311_read_global_reg(pdata->spi,&right_volume,&left_volume);
    pga2311_write_global_reg(pdata->spi,pdata->right_volume,pdata->left_volume);
    return snprintf(buf, PAGE_SIZE, "%d\n",
			left_volume);
}



static struct device_attribute pga2311_attr[] = {
	__ATTR(set_mute_gpio_direction, 0664, NULL, pga2311_mute_store),
	__ATTR(set_zce_gpio_direction, 0664, NULL, pga2311_zce_store),
	__ATTR(right_volume, 0664, pga2311_set_right_volume_show, pga2311_set_right_volume_store),
	__ATTR(left_volume, 0664, pga2311_set_left_volume_show, pga2311_set_left_volume_store),
};

static void pga2311_init_sysfs(struct device *dev)
{
	int i, ret;
	for (i = 0; i < ARRAY_SIZE(pga2311_attr); i++) {
		ret = sysfs_create_file(&dev->kobj,
					&pga2311_attr[i].attr);
		if (ret)
			dev_err(dev, "create charger node(%s) error\n",
				pga2311_attr[i].attr.name);
	}
}


static int pga2311_parse_dt(struct pga2311_data_t *pdata)
{
    int gpio;
    enum of_gpio_flags flags;
    struct device *dev = &pdata->spi->dev;
    int ret;
    struct device_node *node = dev->of_node;

    if (!node)
       return -ENODEV;

	gpio = of_get_named_gpio_flags(node, "gpio_mute", 0, &flags);
	if (gpio_is_valid(gpio))
	{
	    pdata->gpio_mute        = gpio;
	    pdata->gpio_mute_output = (flags == GPIO_ACTIVE_HIGH)? 1:0;	    
	    printk(KERN_ERR"gpio_mute: %d\n", pdata->gpio_mute);
	    
	    ret = devm_gpio_request(dev,gpio, "gpio_mute");
	    if (ret) {
			printk("Failed to get gpio_mute gpio.\n");
		}
		pdata->gpio_mute_is_valid = 1;
	}

	gpio = of_get_named_gpio_flags(node, "gpio_zero_crossing_enable", 0,&flags);
	if (gpio_is_valid(gpio))
	{
	    pdata->gpio_zce        = gpio;
	    pdata->gpio_zce_output = (flags == GPIO_ACTIVE_HIGH)? 1:0;
		printk(KERN_ERR"gpio_zero_crossing_enable: %d\n", pdata->gpio_zce);

		ret = devm_gpio_request(dev,gpio, "gpio_zero_crossing_enable");
	    if (ret) {
			printk("Failed to get gpio_zero_crossing_enable gpio.\n");
		}
		pdata->gpio_zce_is_valid = 1;
	}

	if (pdata->gpio_mute_is_valid == 1) {   //set mute to default
	    gpio_direction_output(pdata->gpio_mute, pdata->gpio_mute_output);
	}

	if (pdata->gpio_zce_is_valid == 1) {   //set zero crossing enable to default
	    gpio_direction_output(pdata->gpio_zce, pdata->gpio_zce_output);
	}
	
	return 0;
}

static int pga2311_probe(struct spi_device *spi)
{ 
    int ret = 0; 

    if (!spi)
       return -ENOMEM;

    dev_err(&spi->dev, "pga2311_probe: setup mode %d, %s%s%s%s%u bits/w, %u Hz max\n",
       		(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
       		(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
       		(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
       		(spi->mode & SPI_3WIRE) ? "3wire, " : "",
       		(spi->mode & SPI_LOOP) ? "loopback, " : "",
       		 spi->bits_per_word, spi->max_speed_hz);
       		 
    ret = spi_setup(spi);
    if (ret < 0) {
        dev_err(&spi->dev,"ERR: fail to setup spi\n");
        return -1;
    }
      
       
    p_pga2311_data = kmalloc(sizeof(struct pga2311_data_t), GFP_KERNEL);
    if (p_pga2311_data == NULL) {
        printk(KERN_ERR"kmalloc pga2311_data_t err \n");
        return -ENOMEM;
    }

    memset(p_pga2311_data, 0, sizeof(struct pga2311_data_t));
    
    p_pga2311_data->spi = spi;

    if (pga2311_parse_dt(p_pga2311_data)) {
        printk(KERN_ERR"pga2311_parse_dt err \n");
        goto err;
    }

    pga2311_init_sysfs(&p_pga2311_data->spi->dev);
    
    return 0;
    
err:
    kfree(p_pga2311_data);
    return -1;
}


static const struct of_device_id pga2311_dt_match[] = {
    { .compatible = "ti,pga2311", },
	{ },
};

MODULE_DEVICE_TABLE(of, pga2311_dt_match);

static struct spi_driver pga2311_driver = {
    .driver = {
        .name           = "pga2311",
        .bus            = &spi_bus_type,
        .owner          = THIS_MODULE,
	    .of_match_table = of_match_ptr(pga2311_dt_match),
    },
    .probe          = pga2311_probe,
};


static int __init pga2311_init(void)
{
     int retval;
     retval = spi_register_driver(&pga2311_driver);
     printk(KERN_ALERT "%s,register spi return v = :%d\n",__func__,retval);
     return retval;
}

static void __exit pga2311_exit(void)
{
     printk(KERN_ALERT "%s!!--in--\n", __func__);
     return spi_unregister_driver(&pga2311_driver);
}

module_init(pga2311_init);
module_exit(pga2311_exit);

MODULE_AUTHOR("System Application Group");
MODULE_DESCRIPTION("pga2311 driver");
MODULE_LICENSE("GPL");

···
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值