android_kernel_samsung_hero.../drivers/adsp_factory/ak09911c_mag.c
2016-08-17 16:41:52 +08:00

351 lines
10 KiB
C

/*
* Copyright (C) 2012, Samsung Electronics Co. Ltd. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/module.h>
#include "adsp.h"
#define VENDOR "AKM"
#define CHIP_ID "AK09911C"
#define RAWDATA_TIMER_MS 200
#define RAWDATA_TIMER_MARGIN_MS 20
#define MAG_SELFTEST_TRY_CNT 7
#define AK09911C_MODE_POWERDOWN 0x00
static int mag_read_fuserom(struct device *dev,
struct device_attribute *attr)
{
struct adsp_data *data = dev_get_drvdata(dev);
unsigned long timeout;
struct msg_data message;
message.sensor_type = ADSP_FACTORY_MAG;
msleep(RAWDATA_TIMER_MS + RAWDATA_TIMER_MARGIN_MS);
adsp_unicast(&message, sizeof(message), NETLINK_MESSAGE_MAG_READ_FUSE_ROM, 0, 0);
timeout = jiffies + (20 * HZ);
while (!(data->magtest_ready_flag & 1 << ADSP_FACTORY_MAG)) {
msleep(20);
if (time_after(jiffies, timeout)) {
pr_info("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
}
data->magtest_ready_flag &= 0 << ADSP_FACTORY_MAG;
#if 0
pr_info("[FACTORY] %s: mag_x(%d), mag_y(%d), mag_z(%d)\n", __func__,
data->sensor_mag_factory_result.fuserom_x,
data->sensor_mag_factory_result.fuserom_y,
data->sensor_mag_factory_result.fuserom_z);
#endif
return 0;
}
static int mag_read_register(struct device *dev,
struct device_attribute *attr)
{
struct adsp_data *data = dev_get_drvdata(dev);
unsigned long timeout;
struct msg_data message;
message.sensor_type = ADSP_FACTORY_MAG;
msleep(RAWDATA_TIMER_MS + RAWDATA_TIMER_MARGIN_MS);
adsp_unicast(&message, sizeof(message), NETLINK_MESSAGE_MAG_READ_REGISTERS, 0, 0);
timeout = jiffies + (20 * HZ);
while (!(data->magtest_ready_flag & 1 << ADSP_FACTORY_MAG)) {
msleep(20);
if (time_after(jiffies, timeout)) {
pr_info("[FACTORY] %s: Timeout!!!\n", __func__);
return -1;
}
}
data->magtest_ready_flag &= 0 << ADSP_FACTORY_MAG;
#if 1
pr_info("[FACTORY] %s: result(%d), mag_x(%d), mag_y(%d), mag_z(%d)\n", __func__,
data->sensor_mag_factory_result.result,
data->sensor_mag_factory_result.registers[0],
data->sensor_mag_factory_result.registers[1],
data->sensor_mag_factory_result.registers[2]);
#endif
if(data->sensor_mag_factory_result.result == -1)
return -1;
else
return 0;
}
static ssize_t mag_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", VENDOR);
}
static ssize_t mag_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", CHIP_ID);
}
static ssize_t mag_read_adc(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
if (adsp_start_raw_data(ADSP_FACTORY_MAG) == false)
return snprintf(buf, PAGE_SIZE, "%s,%d,%d,%d\n", "NG", 0, 0, 0);
pr_info("[FACTORY] %s: %d,%d,%d,%d\n", __func__, true,
data->sensor_data[ADSP_FACTORY_MAG].x,
data->sensor_data[ADSP_FACTORY_MAG].y,
data->sensor_data[ADSP_FACTORY_MAG].z);
return snprintf(buf, PAGE_SIZE, "%s,%d,%d,%d\n", "OK",
data->sensor_data[ADSP_FACTORY_MAG].x,
data->sensor_data[ADSP_FACTORY_MAG].y,
data->sensor_data[ADSP_FACTORY_MAG].z);
}
static ssize_t mag_check_cntl(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int8_t reg;
reg = mag_read_register(dev, attr);
if(reg < 0) {
data->sensor_mag_factory_result.registers[13] = 0;
pr_info("[FACTORY] %s: failed!! = %d\n",
__func__, reg);
}
return snprintf(buf, PAGE_SIZE, "%s\n",
(((data->sensor_mag_factory_result.registers[13] == AK09911C_MODE_POWERDOWN) &&
(reg == 0)) ? "OK" : "NG"));
}
static ssize_t mag_check_registers(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
uint8_t temp[13];
uint8_t ret = 0;
int8_t reg;
reg = mag_read_register(dev, attr);
if (reg < 0) {
for (ret = 0; ret < 13; ret++) {
data->sensor_mag_factory_result.registers[ret] = 0;
temp[ret] = 0;
}
pr_info("[FACTORY] %s: failed!! = %d\n",
__func__, reg);
} else {
for (ret = 0; ret < 13; ret++)
temp[ret] = (uint8_t)(data->sensor_mag_factory_result.registers[ret]);
}
return snprintf(buf, PAGE_SIZE,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
temp[0], temp[1], temp[2], temp[3], temp[4], temp[5],
temp[6], temp[7], temp[8], temp[9], temp[10], temp[11],
temp[12]);
}
static ssize_t mag_get_asa(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int success;
success = mag_read_fuserom(dev, attr);
if (success < 0) {
data->sensor_mag_factory_result.fuserom_x = 0;
data->sensor_mag_factory_result.fuserom_y = 0;
data->sensor_mag_factory_result.fuserom_z = 0;
pr_info("[FACTORY] %s: failed!! = %d\n",
__func__, success);
}
return snprintf(buf, PAGE_SIZE, "%u,%u,%u\n",
data->sensor_mag_factory_result.fuserom_x,
data->sensor_mag_factory_result.fuserom_y,
data->sensor_mag_factory_result.fuserom_z);
}
static ssize_t mag_get_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int success;
success = mag_read_fuserom(dev, attr);
if (success < 0) {
data->sensor_mag_factory_result.fuserom_x = 0;
data->sensor_mag_factory_result.fuserom_y = 0;
data->sensor_mag_factory_result.fuserom_z = 0;
pr_info("[FACTORY] %s: failed!! = %d\n",
__func__, success);
success = false;
}
if ((data->sensor_mag_factory_result.fuserom_x == 0)
|| (data->sensor_mag_factory_result.fuserom_x == 0xff)
|| (data->sensor_mag_factory_result.fuserom_y == 0)
|| (data->sensor_mag_factory_result.fuserom_y == 0xff)
|| (data->sensor_mag_factory_result.fuserom_z == 0)
|| (data->sensor_mag_factory_result.fuserom_z == 0xff))
success = false;
else
success = true;
return snprintf(buf, PAGE_SIZE, "%s\n", (success ? "OK" : "NG"));
}
static ssize_t mag_raw_data_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
static uint8_t sample_cnt = 0;
struct adsp_data *data = dev_get_drvdata(dev);
if (adsp_start_raw_data(ADSP_FACTORY_MAG) == false)
return snprintf(buf, PAGE_SIZE, "%d\n", 0);
sample_cnt++;
if (sample_cnt > 20) { /* sample log 1.6s */
sample_cnt = 0;
pr_info("[FACTORY] %s: %d,%d,%d\n", __func__,
data->sensor_data[ADSP_FACTORY_MAG].x,
data->sensor_data[ADSP_FACTORY_MAG].y,
data->sensor_data[ADSP_FACTORY_MAG].z);
}
return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n",
data->sensor_data[ADSP_FACTORY_MAG].x,
data->sensor_data[ADSP_FACTORY_MAG].y,
data->sensor_data[ADSP_FACTORY_MAG].z);
}
static ssize_t mag_selttest_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adsp_data *data = dev_get_drvdata(dev);
int result1 = 0;
int temp[10];
unsigned long timeout;
struct msg_data message;
uint8_t ret;
uint8_t retry = 0;
retry_mag_selftest:
message.sensor_type = ADSP_FACTORY_MAG;
msleep(RAWDATA_TIMER_MS + RAWDATA_TIMER_MARGIN_MS);
adsp_unicast(&message, sizeof(message), NETLINK_MESSAGE_SELFTEST_SHOW_DATA, 0, 0);
timeout = jiffies + (20 * HZ);
while (!(data->selftest_ready_flag & 1 << ADSP_FACTORY_MAG)) {
msleep(20);
if (time_after(jiffies, timeout)) {
data->sensor_selftest_result[ADSP_FACTORY_MAG].result1 = -1;
pr_info("[FACTORY] %s: Timeout!!!\n", __func__);
}
}
data->selftest_ready_flag &= 0 << ADSP_FACTORY_MAG;
temp[0] = data->sensor_selftest_result[ADSP_FACTORY_MAG].result1;
temp[1] = data->sensor_selftest_result[ADSP_FACTORY_MAG].result2;
temp[2] = data->sensor_selftest_result[ADSP_FACTORY_MAG].offset_x;
temp[3] = data->sensor_selftest_result[ADSP_FACTORY_MAG].offset_y;
temp[4] = data->sensor_selftest_result[ADSP_FACTORY_MAG].offset_z;
temp[5] = data->sensor_selftest_result[ADSP_FACTORY_MAG].dac_ret;
temp[6] = data->sensor_selftest_result[ADSP_FACTORY_MAG].adc_ret;
temp[7] = data->sensor_selftest_result[ADSP_FACTORY_MAG].ohx;
temp[8] = data->sensor_selftest_result[ADSP_FACTORY_MAG].ohy;
temp[9] = data->sensor_selftest_result[ADSP_FACTORY_MAG].ohz;
/* Data Process */
if (temp[0] == 0)
result1 = 1;
else
result1 = 0;
pr_info("[FACTORY] status=%d, sf_status=%d, sf_x=%d, sf_y=%d, sf_z=%d\n"
"[FACTORY] dac_status=%d, adc_status=%d, adc_x=%d, adc_y=%d, adc_z=%d\n",
temp[0], temp[1], temp[2], temp[3], temp[4],
temp[5], temp[6], temp[7], temp[8], temp[9]);
if (!result1) {
if (retry < MAG_SELFTEST_TRY_CNT && temp[0] != 0) {
retry++;
msleep(RAWDATA_TIMER_MS * 2);
for (ret = 0; ret < 10; ret++)
temp[ret] = 0;
goto retry_mag_selftest;
}
}
return sprintf(buf,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
temp[0], temp[1], temp[2], temp[3], temp[4],
temp[5], temp[6], temp[7], temp[8], temp[9]);
}
static DEVICE_ATTR(name, S_IRUGO, mag_name_show, NULL);
static DEVICE_ATTR(vendor, S_IRUGO, mag_vendor_show, NULL);
static DEVICE_ATTR(raw_data, S_IRUGO, mag_raw_data_read, NULL);
static DEVICE_ATTR(adc, S_IRUGO, mag_read_adc, NULL);
static DEVICE_ATTR(dac, S_IRUGO, mag_check_cntl, NULL);
static DEVICE_ATTR(chk_registers, S_IRUGO, mag_check_registers, NULL);
static DEVICE_ATTR(selftest, S_IRUSR | S_IRGRP,
mag_selttest_show, NULL);
static DEVICE_ATTR(asa, S_IRUGO, mag_get_asa, NULL);
static DEVICE_ATTR(status, S_IRUGO, mag_get_status, NULL);
static struct device_attribute *mag_attrs[] = {
&dev_attr_name,
&dev_attr_vendor,
&dev_attr_raw_data,
&dev_attr_adc,
&dev_attr_dac,
&dev_attr_chk_registers,
&dev_attr_selftest,
&dev_attr_asa,
&dev_attr_status,
NULL,
};
static int __init ak09911c_factory_init(void)
{
adsp_factory_register(ADSP_FACTORY_MAG, mag_attrs);
pr_info("[FACTORY] %s\n", __func__);
return 0;
}
static void __exit ak09911c_factory_exit(void)
{
adsp_factory_unregister(ADSP_FACTORY_MAG);
pr_info("[FACTORY] %s\n", __func__);
}
module_init(ak09911c_factory_init);
module_exit(ak09911c_factory_exit);