asustek: pcbid: Added pcbid kernel module

In kernel space, include <mach/board_asustek.h> to have the following
exported APIs for inquiry
  --asustek_get_tp_type(void);
    *Touch panel vendor

  --asustek_get_lcd_type(void);
    *LCD vendor

  --asustek_get_hw_rev(void);
    *Hardware revision

Below sysfs are created under /sys/devices/platform/asustek_pcbid
  --asustek_pcbid
    *show up pcbid value

  --asustek_chipid
    *show up system UUID as same as ro.serialno

  --asustek_projectid
    *show up project id

Change-Id: Id10c8baf28220fd52754bec069fa1f4e6f456f25
Signed-off-by: paris_yeh <paris_yeh@asus.com>
Reviewed-on: http://mcrd1-5.corpnet.asus/code-review/master/63004
Reviewed-by: Sam hblee <Sam_hblee@asus.com>
Reviewed-on: http://mcrd1-5.corpnet.asus/code-review/master/68055
Reviewed-by: Jive Hwang <jive_hwang@asus.com>
Tested-by: Jive Hwang <jive_hwang@asus.com>
This commit is contained in:
paris_yeh 2012-11-29 17:00:48 +08:00 committed by Iliyan Malchev
parent e906f25ba2
commit 248b681df7
6 changed files with 472 additions and 0 deletions

View file

@ -7,10 +7,20 @@ endmenu
menu "ASUSTek Specific Feature"
config ASUSTEK_PCBID
bool "Support PCBID interface"
default y
depends on MACH_ASUSTEK
help
PCBID interfaces to support multiple board/peripheral/RF
configurations
config ASUSTEK_KEYPAD
bool "Support ASUSTek GPIO keypad"
depends on MACH_ASUSTEK
default y
help
Select if the GPIO keyboard is attached
endmenu

View file

@ -3,6 +3,7 @@ subdir-ccflags-$(CONFIG_ARCH_MSM) += -Iarch/arm/mach-msm
-include $(src)/Makefile.board
obj-$(CONFIG_MACH_ASUSTEK) += devices_asustek.o
obj-$(CONFIG_ASUSTEK_PCBID) += asustek-pcbid.o
obj-$(CONFIG_ASUSTEK_KEYPAD) += asustek-keypad.o
CFLAGS_devices_asustek.o += -Idrivers/staging/android

View file

@ -0,0 +1,324 @@
/*
* arch/arm/mach-msm/asustek/asustek-pcbid.c
*
* Copyright (C) 2012 ASUSTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/string.h>
#include <mach/board_asustek.h>
#define PCBID_VALUE_INVALID 0x4E2F4100 /* N/A */
enum {
DEBUG_STATE = 1U << 0,
DEBUG_VERBOSE = 1U << 1,
};
static int debug_mask = DEBUG_STATE;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
static unsigned int asustek_pcbid = PCBID_VALUE_INVALID;
static const char *asustek_chipid;
static unsigned int tp_type_pcbid[] = {0, 1};
static unsigned int lcd_type_pcbid[] = {2, 3};
static unsigned int hw_rev_pcbid[] = {4, 5};
struct pcbid_maps
{
unsigned char name[16];
unsigned int *pcbid;
unsigned int pcbid_num;
} asustek_pcbid_maps[] = {
{"TP_TYPE", tp_type_pcbid, ARRAY_SIZE(tp_type_pcbid)},
{"LCD_TYPE", lcd_type_pcbid, ARRAY_SIZE(lcd_type_pcbid)},
{"HW_REV", hw_rev_pcbid, ARRAY_SIZE(hw_rev_pcbid)},
};
#define NUM_MAPS (sizeof asustek_pcbid_maps / sizeof asustek_pcbid_maps[0])
int get_pcbid_type(const char *func)
{
int i = 0, ret = 0;
struct pcbid_maps *map = NULL;
if (asustek_pcbid == PCBID_VALUE_INVALID) {
pr_err("ASUSTek PCBID was invalid\n");
return -ENODEV;
}
for (i = 0; i < NUM_MAPS; i++) {
if (!strcmp(func, asustek_pcbid_maps[i].name)) {
if (debug_mask & DEBUG_VERBOSE)
pr_info("%s was found\n", func);
map = &asustek_pcbid_maps[i];
break;
}
}
if (map) {
/* found */
for (i = 0; i < map->pcbid_num; i++) {
ret += asustek_pcbid & BIT(map->pcbid[i]);
}
ret = ret >> map->pcbid[0];
}
else
ret = -ENODEV;
return ret;
}
tp_type asustek_get_tp_type(void)
{
tp_type ret = TP_TYPE_INVALID;
ret = get_pcbid_type("TP_TYPE");
if (debug_mask & DEBUG_VERBOSE)
pr_info("%s: %d\n", __func__, ret);
if ((ret == -ENODEV) || (ret >= TP_TYPE_MAX))
ret = TP_TYPE_INVALID;
return ret;
}
EXPORT_SYMBOL(asustek_get_tp_type);
lcd_type asustek_get_lcd_type(void)
{
lcd_type ret = LCD_TYPE_INVALID;
ret = get_pcbid_type("LCD_TYPE");
if (debug_mask & DEBUG_VERBOSE)
pr_info("%s: %d\n", __func__, ret);
if ((ret == -ENODEV) || (ret >= LCD_TYPE_MAX))
ret = LCD_TYPE_INVALID;
return ret;
}
EXPORT_SYMBOL(asustek_get_lcd_type);
/* for asustek board revision */
static hw_rev asustek_hw_rev = HW_REV_INVALID;
static int __init hw_rev_setup(char *hw_rev_info)
{
/* CAUTION: These strings comes from bootloader. */
char *hw_rev_str[] = {"SR1", "ER", "PR", "MP"};
unsigned int i;
if (debug_mask & DEBUG_STATE)
pr_info("HW Revision: ASUSTek input %s \n", hw_rev_info);
for (i = 0; i < HW_REV_MAX; i++) {
if (!strcmp(hw_rev_info, hw_rev_str[i])) {
asustek_hw_rev = (hw_rev) i;
break;
}
}
if (i == HW_REV_MAX) {
pr_info("HW Revision: ASUSTek mismatched\n");
return 1;
}
if (debug_mask & DEBUG_STATE)
pr_info("HW Revision: ASUSTek matched %s \n",
hw_rev_str[asustek_hw_rev]);
return 1;
}
__setup("asustek.hw_rev=", hw_rev_setup);
hw_rev asustek_get_hw_rev(void)
{
hw_rev ret = asustek_hw_rev;
/* if valid hardware rev was inputed by bootloader */
if (ret != HW_REV_INVALID)
return ret;
ret = get_pcbid_type("HW_REV");
if (debug_mask & DEBUG_VERBOSE)
pr_info("%s: %d\n", __func__, ret);
if ((ret == -ENODEV) || (ret >= HW_REV_MAX))
ret = HW_REV_INVALID;
return ret;
}
EXPORT_SYMBOL(asustek_get_hw_rev);
#define ASUSTEK_PCBID_ATTR(module) \
static struct kobj_attribute module##_attr = { \
.attr = { \
.name = __stringify(module), \
.mode = 0444, \
}, \
.show = module##_show, \
}
static ssize_t asustek_pcbid_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
char *s = buf;
s += sprintf(s, "%03x\n", asustek_pcbid);
return s - buf;
}
static ssize_t asustek_projectid_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
char *s = buf;
s += sprintf(s, "%02x\n", (asustek_pcbid >> 7) & 0x3);
return s - buf;
}
static ssize_t asustek_chipid_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
char *s = buf;
s += sprintf(s, "%s\n", asustek_chipid);
return s - buf;
}
ASUSTEK_PCBID_ATTR(asustek_pcbid);
ASUSTEK_PCBID_ATTR(asustek_projectid);
ASUSTEK_PCBID_ATTR(asustek_chipid);
static struct attribute *attr_list[] = {
&asustek_pcbid_attr.attr,
&asustek_projectid_attr.attr,
&asustek_chipid_attr.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = attr_list,
};
static int __init pcbid_driver_probe(struct platform_device *pdev)
{
int i, ret = 0;
struct resource *res;
struct asustek_pcbid_platform_data *pdata;
if (!pdev)
return -EINVAL;
pdata = pdev->dev.platform_data;
if (pdata)
asustek_chipid = kstrdup(pdata->UUID, GFP_KERNEL);
asustek_pcbid = 0;
for (i = 0; i < pdev->num_resources; i++) {
res = platform_get_resource(pdev, IORESOURCE_IO, i);
if (!res)
return -ENODEV;
if (debug_mask & DEBUG_VERBOSE)
pr_info("ASUSTek: Requesting gpio%d for %s\n",
res->start, res->name);
ret = gpio_request(res->start, res->name);
if (ret) {
/* indicate invalid pcbid value when error happens */
pr_err("ASUSTek: Failed to request gpio%d for %s\n",
res->start, res->name);
asustek_pcbid = PCBID_VALUE_INVALID;
res = NULL;
break;
}
gpio_direction_input(res->start);
asustek_pcbid |= gpio_get_value(res->start) << i;
}
if (asustek_pcbid == PCBID_VALUE_INVALID) {
/* error handler to free allocated gpio resources */
while (i >= 0) {
res = platform_get_resource(pdev, IORESOURCE_IO, i);
if (!res)
return -ENODEV;
if (debug_mask & DEBUG_VERBOSE)
pr_info("ASUSTek: Freeing gpio%d for %s\n",
res->start, res->name);
gpio_free(res->start);
i--;
}
}
else {
/* report pcbid info to dmesg */
if (debug_mask && DEBUG_STATE)
pr_info("ASUSTek: PCBID=%03x\n", asustek_pcbid);
/* create a sysfs interface */
ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
if (ret)
pr_err("ASUSTek: Failed to create sysfs group\n");
}
return ret;
}
static int __devexit pcbid_driver_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver asustek_pcbid_driver __refdata = {
.probe = pcbid_driver_probe,
.remove = __devexit_p(pcbid_driver_remove),
.driver = {
.name = "asustek_pcbid",
.owner = THIS_MODULE,
},
};
static int __init asustek_pcbid_init(void)
{
return platform_driver_register(&asustek_pcbid_driver);
}
static void __exit asustek_pcbid_exit(void)
{
platform_driver_unregister(&asustek_pcbid_driver);
}
module_init(asustek_pcbid_init);
module_exit(asustek_pcbid_exit);
MODULE_DESCRIPTION("ASUSTek PCBID driver");
MODULE_AUTHOR("Paris Yeh <paris_yeh@asus.com>");
MODULE_LICENSE("GPL");

View file

@ -92,3 +92,96 @@ void __init asustek_add_ramconsole_devices(void)
platform_device_register(&ram_console_device);
}
#endif /* CONFIG_ANDROID_RAM_CONSOLE */
#ifdef CONFIG_ASUSTEK_PCBID
static char serialno[32] = {0,};
int __init asustek_androidboot_serialno(char *s)
{
int n;
if (*s == '=')
s++;
n = snprintf(serialno, sizeof(serialno), "%s", s);
serialno[n] = '\0';
return 1;
}
__setup("androidboot.serialno", asustek_androidboot_serialno);
struct asustek_pcbid_platform_data asustek_pcbid_pdata = {
.UUID = serialno,
};
static struct resource resources_asustek_pcbid[] = {
{
.start = 57,
.end = 57,
.name = "PCB_ID0",
.flags = IORESOURCE_IO,
},
{
.start = 59,
.end = 59,
.name = "PCB_ID1",
.flags = IORESOURCE_IO,
},
{
.start = 12,
.end = 12,
.name = "PCB_ID2",
.flags = IORESOURCE_IO,
},
{
.start = 1,
.end = 1,
.name = "PCB_ID3",
.flags = IORESOURCE_IO,
},
{
.start = 14,
.end = 14,
.name = "PCB_ID4",
.flags = IORESOURCE_IO,
},
{
.start = 15,
.end = 15,
.name = "PCB_ID5",
.flags = IORESOURCE_IO,
},
{
.start = 51,
.end = 51,
.name = "PCB_ID6",
.flags = IORESOURCE_IO,
},
{
.start = 28,
.end = 28,
.name = "PCB_ID7",
.flags = IORESOURCE_IO,
},
{
.start = 86,
.end = 86,
.name = "PCB_ID8",
.flags = IORESOURCE_IO,
},
};
static struct platform_device asustek_pcbid_device = {
.name = "asustek_pcbid",
.id = -1,
.num_resources = ARRAY_SIZE(resources_asustek_pcbid),
.resource = resources_asustek_pcbid,
.dev = {
.platform_data = &asustek_pcbid_pdata,
}
};
void __init asustek_add_pcbid_devices(void)
{
platform_device_register(&asustek_pcbid_device);
}
#endif

View file

@ -3002,6 +3002,9 @@ static void __init apq8064_common_init(void)
pr_err("Failed to initialize XO votes\n");
msm_clock_init(&apq8064_clock_init_data);
apq8064_init_gpiomux();
#ifdef CONFIG_MACH_ASUSTEK
asustek_add_pcbid_devices();
#endif
apq8064_i2c_init();
register_i2c_devices();

View file

@ -28,6 +28,35 @@
#define ASUSTEK_RAM_CONSOLE_SIZE (124 * SZ_1K * 2)
#endif
typedef enum {
TP_TYPE_INVALID = -1,
TP_TYPE_A = 0,
TP_TYPE_B = 1,
TP_TYPE_C = 2,
TP_TYPE_D = 3,
TP_TYPE_MAX
} tp_type;
typedef enum {
LCD_TYPE_INVALID = -1,
LCD_TYPE_A = 0,
LCD_TYPE_B = 1,
LCD_TYPE_MAX
} lcd_type;
typedef enum {
HW_REV_INVALID = -1,
HW_REV_SR1 = 0,
HW_REV_ER = 1,
HW_REV_PR = 2,
HW_REV_MP = 3,
HW_REV_MAX
} hw_rev;
struct asustek_pcbid_platform_data {
const char *UUID;
};
void __init asustek_reserve(void);
#ifdef CONFIG_ANDROID_PERSISTENT_RAM
@ -56,4 +85,16 @@ static inline void __init asustek_add_keypad(void)
/* empty */
}
#endif
#ifdef CONFIG_ASUSTEK_PCBID
void __init asustek_add_pcbid_devices(void);
tp_type asustek_get_tp_type(void);
lcd_type asustek_get_lcd_type(void);
hw_rev asustek_get_hw_rev(void);
#endif
#endif // __ASM_ARCH_MSM_BOARD_ASUSTEK_H