235 lines
5.3 KiB
C
235 lines
5.3 KiB
C
/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/version.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/param.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/gpio.h>
|
|
#include <mach/gpio.h>
|
|
#include <mach/vreg.h>
|
|
#include <mach/gpiomux.h>
|
|
|
|
#define VERSION "1.0"
|
|
struct dentry *pin_debugfs_dent;
|
|
|
|
/* UART GPIO lines for 8660 */
|
|
enum uartpins {
|
|
UARTDM_TX = 53,
|
|
UARTDM_RX = 54,
|
|
UARTDM_CTS = 55,
|
|
UARTDM_RFR = 56
|
|
};
|
|
|
|
/* Aux PCM GPIO lines for 8660 */
|
|
enum auxpcmpins {
|
|
AUX_PCM_CLK = 114,
|
|
AUX_PCM_SYNC = 113,
|
|
AUX_PCM_DIN = 112,
|
|
AUX_PCM_DOUT = 111
|
|
};
|
|
/*Number of UART and PCM pins */
|
|
#define PIN_COUNT 8
|
|
|
|
static struct gpiomux_setting pin_test_config = {
|
|
.func = GPIOMUX_FUNC_GPIO,
|
|
.drv = GPIOMUX_DRV_2MA,
|
|
.pull = GPIOMUX_PULL_NONE,
|
|
};
|
|
/* Static array to intialise the return config */
|
|
static struct gpiomux_setting currentconfig[2*PIN_COUNT];
|
|
|
|
static struct msm_gpiomux_config pin_test_configs[] = {
|
|
{
|
|
.gpio = AUX_PCM_DOUT,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = AUX_PCM_DIN,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = AUX_PCM_SYNC,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = AUX_PCM_CLK,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = UARTDM_TX,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = UARTDM_RX,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = UARTDM_CTS,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
{
|
|
.gpio = UARTDM_RFR,
|
|
.settings = {
|
|
[GPIOMUX_ACTIVE] = &pin_test_config,
|
|
[GPIOMUX_SUSPENDED] = &pin_test_config,
|
|
},
|
|
},
|
|
};
|
|
static struct msm_gpiomux_config pin_config[PIN_COUNT];
|
|
|
|
static int pintest_open(struct inode *inode, struct file *file)
|
|
{
|
|
/* non-seekable */
|
|
file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
|
|
return 0;
|
|
}
|
|
|
|
static int pintest_release(struct inode *inode, struct file *file)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int configure_pins(struct msm_gpiomux_config *config,
|
|
struct msm_gpiomux_config *oldconfig,
|
|
unsigned int num_configs)
|
|
{
|
|
int rc = 0, j, i;
|
|
for (i = 0; i < num_configs; i++) {
|
|
for (j = 0; j < GPIOMUX_NSETTINGS; j++) {
|
|
(oldconfig + i)->gpio = (config + i)->gpio;
|
|
rc = msm_gpiomux_write((config + i)->gpio,
|
|
j,
|
|
(config + i)->settings[j],
|
|
(oldconfig + i)->settings[j]);
|
|
if (rc < 0)
|
|
break;
|
|
}
|
|
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static void init_current_config_pointers(void)
|
|
{
|
|
int i = 0, j = 0;
|
|
/* The current config variables will hold the current configuration
|
|
* which is getting overwritten during a msm_gpiomux_write call
|
|
*/
|
|
for (i = 0, j = 0; i < PIN_COUNT; i += 1, j += 2) {
|
|
pin_config[i].settings[GPIOMUX_ACTIVE] = ¤tconfig[j];
|
|
pin_config[i].settings[GPIOMUX_SUSPENDED] =
|
|
¤tconfig[j + 1];
|
|
}
|
|
|
|
}
|
|
|
|
static ssize_t pintest_write(
|
|
struct file *file,
|
|
const char __user *buff,
|
|
size_t count,
|
|
loff_t *ppos)
|
|
{
|
|
char mode;
|
|
int rc = 0;
|
|
|
|
if (count < 1)
|
|
return -EINVAL;
|
|
|
|
if (buff == NULL)
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&mode, buff, count))
|
|
return -EFAULT;
|
|
mode = mode - '0';
|
|
|
|
init_current_config_pointers();
|
|
|
|
if (mode) {
|
|
/* Configure all pin test gpios for the custom settings */
|
|
rc = configure_pins(pin_test_configs, pin_config,
|
|
ARRAY_SIZE(pin_test_configs));
|
|
if (rc < 0)
|
|
return rc;
|
|
} else {
|
|
/* Configure all pin test gpios for the original settings */
|
|
rc = configure_pins(pin_config, pin_test_configs,
|
|
ARRAY_SIZE(pin_test_configs));
|
|
if (rc < 0)
|
|
return rc;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static const struct file_operations pintest_debugfs_fops = {
|
|
.open = pintest_open,
|
|
.release = pintest_release,
|
|
.write = pintest_write,
|
|
};
|
|
|
|
static int __init bluepintest_init(void)
|
|
{
|
|
pin_debugfs_dent = debugfs_create_dir("btpintest", NULL);
|
|
|
|
if (IS_ERR(pin_debugfs_dent)) {
|
|
printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
|
|
__FILE__, __LINE__, PTR_ERR(pin_debugfs_dent));
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (debugfs_create_file("enable", 0644, pin_debugfs_dent,
|
|
0, &pintest_debugfs_fops) == NULL) {
|
|
printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n",
|
|
__FILE__, __LINE__);
|
|
return -ENOMEM;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void __exit bluepintest_exit(void)
|
|
{
|
|
debugfs_remove_recursive(pin_debugfs_dent);
|
|
}
|
|
|
|
module_init(bluepintest_init);
|
|
module_exit(bluepintest_exit);
|
|
|
|
MODULE_DESCRIPTION("Bluetooth Pin Connectivty Test Driver ver %s " VERSION);
|
|
MODULE_LICENSE("GPL v2");
|