blob: 4a582a7277568bb81e32aa1c0296a5d3ca2b3436 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2022 ASRMicro. All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ASRMicro.
* The copyright notice above does not evidence any actual or intended
* publication of such source code.
* This Module contains Proprietary Information of ASRMicro and should be
* treated as Confidential.
* The information in this file is provided for the exclusive use of the
* licensees of ASRMicro.
* Such users have the right to use, modify, and incorporate this code into
* products for purposes authorized by the license agreement provided they
* include this notice and the associated copyright notice with any such
* product.
* The information in this file is provided "AS IS" without warranty.
*
******************************************************************************/
/******************************************************************************
* Include files
******************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/cputype.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/mfd/88pm80x.h>
#include <linux/mfd/pm813.h>
/******************************************************************************
* Macro definitions
******************************************************************************/
#define AUDIO_PA_MAGIC 'y'
#define PA_ENABLE _IO(AUDIO_PA_MAGIC, 'a')
#define PA_DISABLE _IO(AUDIO_PA_MAGIC, 'b')
/******************************************************************************
* Local variable definitions
******************************************************************************/
static struct dentry *pm813pa_control = NULL;
static char msg[10];
static dev_t pm813pa_dev = 0;
static struct class *pm813pa_class;
static struct cdev pm813pa_cdev;
/******************************************************************************
* function definitions
******************************************************************************/
extern int pm813_extern_read(int page, int reg);
extern int pm813_extern_setbits(int page, int reg, unsigned char mask, unsigned char val);
int PMIC_is_PM813(void)
{
int ret = 0;
unsigned int chip_id = 0;
unsigned int val_30 = 0;
unsigned int val_31 = 0;
chip_id = pm813_extern_read(PM813_BASE_PAGE, 0x00);
if ((CHIP_PM813_ID == chip_id) || (CHIP_PM813S_A1_ID == chip_id) || CHIP_PM813S_A0_ID == chip_id) {
val_30 = pm813_extern_read(PM813_BASE_PAGE, 0x30);
val_31 = pm813_extern_read(PM813_BASE_PAGE, 0x31);
printk(KERN_INFO "%s: chip_id=0x%0x, val_30=0x%0x, val_31=0x%0x\n", __FUNCTION__, chip_id, val_30, val_31);
ret = 1;
}
return ret;
}
void enable_PM813_A1_classD(void)
{
if (PMIC_is_PM813()) {
pm813_extern_setbits(PM813_BASE_PAGE, 0x30, 0x03, 0x02);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x02, 0x00);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x01);
//pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x00);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x40, 0x00);
}
return;
}
void disable_PM813_A1_classD(void)
{
if (PMIC_is_PM813()) {
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x40, 0x40);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x00);
//pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x01);
}
return;
}
void enable_PM813_classD(void)
{
if (PMIC_is_PM813()) {
pm813_extern_setbits(PM813_BASE_PAGE, 0x30, 0x03, 0x02);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x02, 0x00);
//pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x01);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x00);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x40, 0x00);
}
return;
}
void disable_PM813_classD(void)
{
if (PMIC_is_PM813()) {
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x40, 0x40);
//pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x00);
pm813_extern_setbits(PM813_BASE_PAGE, 0x31, 0x01, 0x01);
}
return;
}
/******************************************************************************
* functions for debugfs
******************************************************************************/
static ssize_t debugfs_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
printk(KERN_INFO "%s/L%d.\n", __FUNCTION__, __LINE__);
return 0;
}
static ssize_t debugfs_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
int ret = 0;
size_t tmp_count = 0;
memset(msg, 0x00, sizeof(msg));
tmp_count = count;
if (tmp_count >= sizeof(msg)) {
tmp_count = sizeof(msg) - 1;
}
/* copy the content from user space to kernel space */
ret = copy_from_user(msg, user_buf, tmp_count);
if (ret) {
printk(KERN_ALERT "copy from user fail \n");
return -EFAULT;
}
switch (msg[0]) {
case 'c':/* input command# echo c > /sys/kernel/debug/pm813pa */
printk(KERN_INFO "input %c. \n", msg[0]);
disable_PM813_A1_classD();
break;
case 'd':/* input command# echo d > /sys/kernel/debug/pm813pa */
printk(KERN_INFO "input %c. \n", msg[0]);
enable_PM813_A1_classD();
break;
case '0':/* input command# echo 0 > /sys/kernel/debug/pm813pa */
printk(KERN_INFO "input %c to disable pa pm813pa\n", msg[0]);
disable_PM813_classD();
break;
case '1':/* input command# echo 1 > /sys/kernel/debug/pm813pa */
printk(KERN_INFO "input %c to enable pa pm813pa\n", msg[0]);
enable_PM813_classD();
break;
default:/* input command# */
printk(KERN_INFO "input invalid.\n");
break;
}
return tmp_count;
}
static const struct file_operations debugfs_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = debugfs_read,
.write = debugfs_write,
};
static inline int pm813pa_debugfs_init(void)
{
pm813pa_control = debugfs_create_file("pm813pa", S_IRUGO | S_IFREG, NULL, NULL, &debugfs_ops);
if (pm813pa_control == NULL) {
pr_err("create pm813pa debugfs error!\n");
return -ENOENT;
}
else if (pm813pa_control == ERR_PTR(-ENODEV)) {
pr_err("CONFIG_DEBUG_FS is not enabled!\n");
return -ENOENT;
}
return 0;
}
static void pm813pa_debugfs_remove(void)
{
if (NULL != pm813pa_control) {
debugfs_remove_recursive(pm813pa_control);
}
return;
}
/******************************************************************************
* functions for cdev
******************************************************************************/
static long cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk(KERN_INFO "%s/L%d, cmd = %d", __FUNCTION__, __LINE__, cmd);
switch (cmd) {
case PA_ENABLE:
printk(KERN_INFO "enable pa pm813pa\n");
enable_PM813_classD();
break;
case PA_DISABLE:
printk(KERN_INFO "disable pa pm813pa\n");
disable_PM813_classD();
break;
default:
pr_info("Default\n");
break;
}
return 0;
}
static struct file_operations cdev_fops =
{
.owner = THIS_MODULE,
.open = simple_open,
.unlocked_ioctl = cdev_ioctl,
};
static int pm813pa_cdev_init(void)
{
/*Allocating Major number*/
if ((alloc_chrdev_region(&pm813pa_dev, 0, 1, "pm813pa_Dev")) < 0) {
pr_err("Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "%s/L%d, Major = %d, Minor = %d\n", __FUNCTION__, __LINE__, MAJOR(pm813pa_dev), MINOR(pm813pa_dev));
/*Creating cdev structure*/
cdev_init(&pm813pa_cdev, &cdev_fops);
/*Adding character device to the system*/
if ((cdev_add(&pm813pa_cdev, pm813pa_dev, 1)) < 0) {
pr_err("Cannot add the device to the system\n");
unregister_chrdev_region(pm813pa_dev, 1);
return -1;
}
/*Creating struct class*/
if ((pm813pa_class = class_create(THIS_MODULE, "pm813pa_class")) == NULL) {
pr_err("Cannot create the struct class\n");
unregister_chrdev_region(pm813pa_dev, 1);
return -2;
}
/*Creating device*/
if ((device_create(pm813pa_class, NULL, pm813pa_dev, NULL, "audio_pa")) == NULL) {
pr_err("Cannot create the Device 1\n");
class_destroy(pm813pa_class);
unregister_chrdev_region(pm813pa_dev, 1);
return -1;
}
return 0;
}
static void pm813pa_cdev_exit(void)
{
device_destroy(pm813pa_class, pm813pa_dev);
class_destroy(pm813pa_class);
cdev_del(&pm813pa_cdev);
unregister_chrdev_region(pm813pa_dev, 1);
pr_info("Device Driver Remove...Done!!!\n");
}
/******************************************************************************
* functions for module
******************************************************************************/
static int pm813pa_init(void)
{
printk(KERN_INFO "%s/L%d.\n", __FUNCTION__, __LINE__);
pm813pa_cdev_init();
pm813pa_debugfs_init();
return 0;
}
static void pm813pa_exit(void)
{
pm813pa_cdev_exit();
pm813pa_debugfs_remove();
}
module_init(pm813pa_init);
module_exit(pm813pa_exit);
MODULE_DESCRIPTION("Driver for PM813PA");
MODULE_AUTHOR("yjgwang@asrmicro.com");
MODULE_LICENSE("GPL");