summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authormattis fjallstrom <mattis@acm.org>2015-05-21 12:00:33 -0700
committermattis fjallstrom <mattis@acm.org>2015-05-21 13:24:30 -0700
commit7d990a059acf5eb46ae99c058fc9911cbdce131d (patch)
treeac9531b3ff2b2670dabc84c248a1770c84109586 /drivers
parente8980e2a6a7392ae5a1f882d1ba01e03ac83f899 (diff)
parent89fdc2c4bb83fff36199cd883a27efb317f02037 (diff)
downloadolio-linux-3.10-7d990a059acf5eb46ae99c058fc9911cbdce131d.tar.xz
olio-linux-3.10-7d990a059acf5eb46ae99c058fc9911cbdce131d.zip
Merge branch 'android-omap-minnow-3.10-lollipop-wear-release' of https://android.googlesource.com/kernel/omap into mattis_devmattis_dev
Change-Id: I46165dd7747b9b6289eb44cb96cbef2de46c10ba
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/firmware_class.c46
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c8
-rwxr-xr-xdrivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c2
-rw-r--r--drivers/leds/leds-lm3535.c158
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/m4sensorhub-core.c74
-rw-r--r--drivers/mfd/m4sensorhub-extern.c158
-rw-r--r--drivers/mfd/m4sensorhub-panic.c1
-rw-r--r--drivers/mfd/m4sensorhub-reg.h10
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/als_notify.c50
-rw-r--r--drivers/misc/c55_ctrl.c16
-rw-r--r--drivers/misc/m4sensorhub_als.c118
-rw-r--r--drivers/misc/m4sensorhub_fusion.c84
-rw-r--r--drivers/misc/m4sensorhub_gesture.c8
-rw-r--r--drivers/misc/m4sensorhub_mpu9150.c64
-rw-r--r--drivers/misc/m4sensorhub_pedometer.c194
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/power/avs/Makefile2
-rw-r--r--drivers/power/avs/omap_core_dvfs.c303
-rw-r--r--drivers/power/max17042_battery.c148
-rw-r--r--drivers/regulator/omap-pmic-regulator.c17
-rw-r--r--drivers/rtc/rtc-sensorhub.c3
-rw-r--r--drivers/tty/serial/omap-serial.c8
-rw-r--r--drivers/video/omap2/displays/panel-minnow-common.h6
-rw-r--r--drivers/video/omap2/displays/panel-minnow.c145
27 files changed, 1402 insertions, 232 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 01e21037d8f..d7872b96019 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -27,6 +27,7 @@
#include <linux/pm.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
+#include <linux/reboot.h>
#include <generated/utsrelease.h>
@@ -130,6 +131,7 @@ struct firmware_buf {
struct page **pages;
int nr_pages;
int page_array_size;
+ struct list_head pending_list;
#endif
char fw_id[];
};
@@ -171,6 +173,9 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
strcpy(buf->fw_id, fw_name);
buf->fwc = fwc;
init_completion(&buf->completion);
+#ifdef CONFIG_FW_LOADER_USER_HELPER
+ INIT_LIST_HEAD(&buf->pending_list);
+#endif
pr_debug("%s: fw-%s buf=%p\n", __func__, fw_name, buf);
@@ -446,10 +451,8 @@ static struct firmware_priv *to_firmware_priv(struct device *dev)
return container_of(dev, struct firmware_priv, dev);
}
-static void fw_load_abort(struct firmware_priv *fw_priv)
+static void __fw_load_abort(struct firmware_buf *buf)
{
- struct firmware_buf *buf = fw_priv->buf;
-
/*
* There is a small window in which user can write to 'loading'
* between loading done and disappearance of 'loading'
@@ -457,8 +460,16 @@ static void fw_load_abort(struct firmware_priv *fw_priv)
if (test_bit(FW_STATUS_DONE, &buf->status))
return;
+ list_del_init(&buf->pending_list);
set_bit(FW_STATUS_ABORT, &buf->status);
complete_all(&buf->completion);
+}
+
+static void fw_load_abort(struct firmware_priv *fw_priv)
+{
+ struct firmware_buf *buf = fw_priv->buf;
+
+ __fw_load_abort(buf);
/* avoid user action after loading abort */
fw_priv->buf = NULL;
@@ -467,6 +478,25 @@ static void fw_load_abort(struct firmware_priv *fw_priv)
#define is_fw_load_aborted(buf) \
test_bit(FW_STATUS_ABORT, &(buf)->status)
+static LIST_HEAD(pending_fw_head);
+
+/* reboot notifier for avoid deadlock with usermode_lock */
+static int fw_shutdown_notify(struct notifier_block *unused1,
+ unsigned long unused2, void *unused3)
+{
+ mutex_lock(&fw_lock);
+ while (!list_empty(&pending_fw_head))
+ __fw_load_abort(list_first_entry(&pending_fw_head,
+ struct firmware_buf,
+ pending_list));
+ mutex_unlock(&fw_lock);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block fw_shutdown_nb = {
+ .notifier_call = fw_shutdown_notify,
+};
+
static ssize_t firmware_timeout_show(struct class *class,
struct class_attribute *attr,
char *buf)
@@ -619,6 +649,7 @@ static ssize_t firmware_loading_store(struct device *dev,
* is completed.
* */
fw_map_pages_buf(fw_buf);
+ list_del_init(&fw_buf->pending_list);
complete_all(&fw_buf->completion);
break;
}
@@ -853,8 +884,15 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent,
goto err_del_dev;
}
+ mutex_lock(&fw_lock);
+ list_add(&buf->pending_list, &pending_fw_head);
+ mutex_unlock(&fw_lock);
+
retval = device_create_file(f_dev, &dev_attr_loading);
if (retval) {
+ mutex_lock(&fw_lock);
+ list_del_init(&buf->pending_list);
+ mutex_unlock(&fw_lock);
dev_err(f_dev, "%s: device_create_file failed\n", __func__);
goto err_del_bin_attr;
}
@@ -1526,6 +1564,7 @@ static int __init firmware_class_init(void)
{
fw_cache_init();
#ifdef CONFIG_FW_LOADER_USER_HELPER
+ register_reboot_notifier(&fw_shutdown_nb);
return class_register(&firmware_class);
#else
return 0;
@@ -1539,6 +1578,7 @@ static void __exit firmware_class_exit(void)
unregister_pm_notifier(&fw_cache.pm_notify);
#endif
#ifdef CONFIG_FW_LOADER_USER_HELPER
+ unregister_reboot_notifier(&fw_shutdown_nb);
class_unregister(&firmware_class);
#endif
}
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index dd7bc175ca8..0b9f6a3c66c 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -150,15 +150,22 @@ out:
static int cpu0_cpufreq_pm_notify(struct notifier_block *nb,
unsigned long event, void *dummy)
{
+ static unsigned int old_policy_max;
mutex_lock(&cpu0_cpufreq_lock);
if (event == PM_SUSPEND_PREPARE) {
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
is_suspended = true;
+ old_policy_max = policy->max;
+ policy->max = policy->cpuinfo.max_freq;
pr_debug("cpu0 cpufreq suspend: setting frequency to %d kHz\n",
policy->max);
__cpu0_set_target(policy, policy->max, CPUFREQ_RELATION_L);
cpufreq_cpu_put(policy);
} else if (event == PM_POST_SUSPEND) {
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+ policy->max = old_policy_max;
+ __cpu0_set_target(policy, policy->max, CPUFREQ_RELATION_L);
+ cpufreq_cpu_put(policy);
is_suspended = false;
}
mutex_unlock(&cpu0_cpufreq_lock);
@@ -182,6 +189,7 @@ static int cpu0_cpufreq_reboot_notify(struct notifier_block *nb,
mutex_lock(&cpu0_cpufreq_lock);
policy = cpufreq_cpu_get(0);
is_suspended = true;
+ policy->max = policy->cpuinfo.max_freq;
pr_info("cpu0 cpufreq shutdown: setting frequency to %d kHz\n",
policy->max);
__cpu0_set_target(policy, policy->max, CPUFREQ_RELATION_L);
diff --git a/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c b/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c
index c9b577eddbe..f13d0cfa586 100755
--- a/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c
+++ b/drivers/gpu/pvr/services4/srvkm/env/linux/osfunc.c
@@ -3169,7 +3169,7 @@ PVRSRV_ERROR OSEventObjectSignalKM(IMG_HANDLE hOSEventKM)
******************************************************************************/
IMG_BOOL OSProcHasPrivSrvInit(IMG_VOID)
{
- return (capable(CAP_SYS_MODULE) != 0) ? IMG_TRUE : IMG_FALSE;
+ return (capable(CAP_SYS_ADMIN) != 0) ? IMG_TRUE : IMG_FALSE;
}
/*!
diff --git a/drivers/leds/leds-lm3535.c b/drivers/leds/leds-lm3535.c
index 3f157942803..23b7558674e 100644
--- a/drivers/leds/leds-lm3535.c
+++ b/drivers/leds/leds-lm3535.c
@@ -50,10 +50,11 @@
#ifdef CONFIG_LM3535_ESD_RECOVERY
#include <mot/esd_poll.h>
#endif /* CONFIG_LM3535_ESD_RECOVERY */
-#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
#include <linux/notifier.h>
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+#include <linux/als_notify.h>
#include <linux/wakeup_source_notify.h>
-#define MIN_DOCK_BVALUE 36
+#define MIN_DOCK_BVALUE 36
#include <linux/m4sensorhub.h>
#include <linux/m4sensorhub/MemMapUserSettings.h>
#endif
@@ -273,7 +274,12 @@ struct lm3535 {
int prevent_als_read; /* Whether to prevent als reads for a time */
#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
atomic_t docked;
+ atomic_t alsstatus;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ atomic_t interactive;
+#endif
struct notifier_block dock_nb;
+ struct notifier_block als_nb;
#endif
};
static DEFINE_MUTEX(lm3535_mutex);
@@ -574,30 +580,34 @@ static uint8_t lm3535_convert_value (unsigned value, unsigned zone)
reg = res / als_denom;
#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
- if (!lm3535_data.prevent_als_read) {
- /* make sure this is atleast as high as corresponding ambient
- * mode value for current ALS condition */
- m4sensorhub = m4sensorhub_client_get_drvdata();
- size = m4sensorhub_reg_getsize(m4sensorhub,
- M4SH_REG_LIGHTSENSOR_SIGNAL);
- if (size != sizeof(als)) {
- pr_err("can't get M4 reg size for ALS\n");
- ambient_als_backlight = 0;
- } else if (size != m4sensorhub_reg_read(m4sensorhub,
- M4SH_REG_LIGHTSENSOR_SIGNAL,
- (char *)&als)) {
- pr_err("error reading M4 ALS value\n");
- ambient_als_backlight = 0;
- } else {
- adjust_als = true;
- /* prevent als reads for next 500 ms */
- lm3535_data.prevent_als_read = 1;
- schedule_delayed_work(&lm3535_data.als_delayed_work,
- msecs_to_jiffies(500));
+ if (atomic_read(&lm3535_data.alsstatus)) {
+ if (!lm3535_data.prevent_als_read) {
+ /* make sure this is atleast as
+ high as corresponding ambient
+ * mode value for current ALS condition */
+ m4sensorhub = m4sensorhub_client_get_drvdata();
+ size = m4sensorhub_reg_getsize(m4sensorhub,
+ M4SH_REG_LIGHTSENSOR_SIGNAL);
+ if (size != sizeof(als)) {
+ pr_err("can't get M4 reg size for ALS\n");
+ ambient_als_backlight = 0;
+ } else if (size != m4sensorhub_reg_read(m4sensorhub,
+ M4SH_REG_LIGHTSENSOR_SIGNAL,
+ (char *)&als)) {
+ pr_err("error reading M4 ALS value\n");
+ ambient_als_backlight = 0;
+ } else {
+ adjust_als = true;
+ /* prevent als reads for next 500 ms */
+ lm3535_data.prevent_als_read = 1;
+ schedule_delayed_work(
+ &lm3535_data.als_delayed_work,
+ msecs_to_jiffies(500));
+ }
+ } else if (ambient_als_backlight > reg) {
+ /* If valid, use previously read als value */
+ reg = ambient_als_backlight;
}
- } else if (ambient_als_backlight > reg) {
- /* If valid, use previously read als value */
- reg = ambient_als_backlight;
}
if (adjust_als) {
@@ -606,7 +616,7 @@ static uint8_t lm3535_convert_value (unsigned value, unsigned zone)
if (ambient_als_backlight > reg)
reg = ambient_als_backlight;
}
-#endif
+#endif /* CONFIG_WAKEUP_SOURCE_NOTIFY*/
printk_br(KERN_INFO "%s: v=%d, z=%d, res=0x%x, reg=0x%x\n",
__func__, value, zone, res, reg);
@@ -660,6 +670,31 @@ static void lm3535_brightness_set_raw_als(struct led_classdev *led_cdev,
mutex_unlock(&lm3535_mutex);
}
#endif
+
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+static int lm3535_als_notifier(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ pr_info("%s: ALS value is %lu\n", __func__, action);
+ switch (action) {
+ case ALS_ENABLED:
+ case ALS_DISABLED:
+ atomic_set(&lm3535_data.use_als, (action == ALS_ENABLED));
+ break;
+ default:
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (atomic_read(&lm3535_data.interactive) == 0)
+ lm3535_brightness_set_raw_als(led_get_default_dev(),
+ (unsigned int)action);
+ else
+ pr_info("%s: ignoring ALS notifications\n", __func__);
+#endif
+ break;
+ }
+ return NOTIFY_OK;
+}
+#endif /* CONFIG_WAKEUP_SOURCE_NOTIFY */
+
static void lm3535_brightness_set (struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -707,6 +742,7 @@ static void lm3535_brightness_set (struct led_classdev *led_cdev,
/* Calculate brightness value for each zone relative to its cap */
bvalue = lm3535_convert_value (value, bright_zone);
+
#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
if (atomic_read(&lm3535_data.docked) && (bvalue < MIN_DOCK_BVALUE))
bvalue = MIN_DOCK_BVALUE; /* hard code for dock mode */
@@ -922,6 +958,38 @@ static ssize_t lm3535_suspend_store (struct device *dev,
}
static DEVICE_ATTR(suspend, 0644, lm3535_suspend_show, lm3535_suspend_store);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+static ssize_t lm3535_interactive_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", atomic_read(&lm3535_data.interactive));
+}
+
+static ssize_t lm3535_interactive_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned value = 0;
+
+ if (!buf || size == 0) {
+ pr_err("%s: invalid command\n", __func__);
+ return -EINVAL;
+ }
+
+ sscanf(buf, "%d", &value);
+ if (value)
+ atomic_set(&lm3535_data.interactive, 1);
+ else
+ atomic_set(&lm3535_data.interactive, 0);
+
+ return size;
+}
+static DEVICE_ATTR(interactive, S_IRUGO | S_IWUSR,
+ lm3535_interactive_show,
+ lm3535_interactive_store);
+#endif
+
/* This function is called by i2c_probe */
static int lm3535_probe (struct i2c_client *client,
const struct i2c_device_id *id)
@@ -997,6 +1065,18 @@ static int lm3535_probe (struct i2c_client *client,
misc_deregister (&als_miscdev);
return ret;
}
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ ret = device_create_file(lm3535_led.dev, &dev_attr_interactive);
+ if (ret) {
+ pr_err("err creating interactive file for %s: %d\n",
+ lm3535_led.name, ret);
+ led_classdev_unregister(&lm3535_led);
+ led_classdev_unregister(&lm3535_led_noramp);
+ device_remove_file(lm3535_led.dev, &dev_attr_suspend);
+ misc_deregister(&als_miscdev);
+ return ret;
+ }
+#endif
dev_set_drvdata (lm3535_led.dev, &lm3535_led);
#if 0
lm3535_data.idev = input_allocate_device();
@@ -1029,15 +1109,23 @@ static int lm3535_probe (struct i2c_client *client,
register_early_suspend (&early_suspend_data);
#endif
- lm3535_led.brightness = 255;
- lm3535_led_noramp.brightness = 255;
- //lm3535_brightness_set (&lm3535_led_noramp, 255);
- lm3535_write_reg (LM3535_BRIGHTNESS_CTRL_REG_A, 0x79, __FUNCTION__);
- lm3535_data.initialized = 1;
+ lm3535_led.brightness = 84;
+ lm3535_led_noramp.brightness = 84;
+ /* lm3535_brightness_set (&lm3535_led_noramp, 255); */
+ lm3535_write_reg(LM3535_BRIGHTNESS_CTRL_REG_A, 87, __func__);
+ lm3535_data.initialized = 1;
#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
atomic_set(&lm3535_data.docked, 0);
+ /* default setting for minnow is to use ALS */
+ atomic_set(&lm3535_data.alsstatus, 1);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ atomic_set(&lm3535_data.interactive, 1);
+#endif
lm3535_data.dock_nb.notifier_call = lm3535_dock_notifier;
wakeup_source_register_notify(&lm3535_data.dock_nb);
+
+ lm3535_data.als_nb.notifier_call = lm3535_als_notifier;
+ als_register_notify(&lm3535_data.als_nb);
#endif /* CONFIG_WAKEUP_SOURCE_NOTIFY */
INIT_DELAYED_WORK(&lm3535_data.als_delayed_work,
@@ -1515,10 +1603,18 @@ static int lm3535_remove (struct i2c_client *client)
/* led_classdev_unregister (&lm3535_led_noramp); */
misc_deregister (&als_miscdev);
device_remove_file (lm3535_led.dev, &dev_attr_suspend);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ device_remove_file(lm3535_led.dev, &dev_attr_interactive);
+#endif
#if 0
input_unregister_device (lm3535_data.idev);
input_free_device (lm3535_data.idev);
#endif
+
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ wakeup_source_unregister_notify(&lm3535_data.dock_nb);
+ als_unregister_notify(&lm3535_data.als_nb);
+#endif
return 0;
}
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c0704d70b97..e14fcb9363f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -171,6 +171,7 @@ m4sensorhub-objs := m4sensorhub-core.o \
m4sensorhub-reg.o \
m4sensorhub-irq.o \
m4sensorhub-panic.o \
+ m4sensorhub-extern.o \
m4sensorhub-stm32-fw.o \
m4sensorhub-stm32_401-fw.o
diff --git a/drivers/mfd/m4sensorhub-core.c b/drivers/mfd/m4sensorhub-core.c
index a10ab20280b..203109e6ac7 100644
--- a/drivers/mfd/m4sensorhub-core.c
+++ b/drivers/mfd/m4sensorhub-core.c
@@ -90,6 +90,12 @@ static ssize_t m4sensorhub_get_dbg(struct device *dev,
/* BEGIN BOARD FILE */
/* TODO: replace with request array */
+int m4sensorhub_get_current_mode(void)
+{
+ return m4sensorhub_misc_data.mode;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_get_current_mode);
+
int m4sensorhub_set_bootmode(struct m4sensorhub_data *m4sensorhub,
enum m4sensorhub_bootmode bootmode)
{
@@ -496,6 +502,12 @@ static void m4sensorhub_initialize(const struct firmware *firmware,
return;
}
+ err = m4sensorhub_extern_init(&m4sensorhub_misc_data);
+ if (err < 0) {
+ KDEBUG(M4SH_ERROR, "%s: Extern init failed.\n", __func__);
+ return;
+ }
+
/* Initialize all the m4 drivers */
inc = inithead;
arg.p_m4sensorhub_data = &m4sensorhub_misc_data;
@@ -540,20 +552,27 @@ static DEVICE_ATTR(debug_level, S_IRUSR|S_IWUSR, m4sensorhub_get_dbg,
static ssize_t m4sensorhub_get_loglevel(struct device *dev,
struct device_attribute *attr, char *buf)
{
- unsigned long long loglevel;
+ uint32_t logenable[LOG_EN_SIZE], len, i;
m4sensorhub_reg_read(&m4sensorhub_misc_data,
- M4SH_REG_LOG_LOGENABLE, (char *)&loglevel);
- KDEBUG(M4SH_INFO, "M4 loglevel = %llx", loglevel);
- return sprintf(buf, "%llu\n", loglevel);
+ M4SH_REG_LOG_LOGENABLE, (char *)&logenable);
+
+ len = sprintf(buf, "M4 log levels = 0x");
+ for (i = 0; i < LOG_EN_SIZE; i++)
+ len += sprintf(buf+len, "%08x", logenable[i]);
+ KDEBUG(M4SH_INFO, "%s\n", buf);
+ return snprintf(buf, PAGE_SIZE, "%s\n", buf);
}
-void m4sensorhub_update_loglevels(char *tag, char *level,
- unsigned long long *log_levels)
+void m4sensorhub_update_loglevels(int8_t *tag, int8_t *level,
+ uint32_t *log_level)
{
- int i;
- int levelindex = -1;
- int tagindex = -1;
- unsigned long long mask;
+ uint32_t i;
+ int32_t levelindex = -1;
+ int32_t tagindex = -1;
+ uint32_t mask;
+ int32_t logenableindex;
+ int32_t en = LOG_TAGS_PER_ENABLE;
+ int32_t b = LOG_NO_OF_BITS_PER_TAG;
for (i = 0; i < LOG_LEVELS_MAX; i++) {
if (strcmp(acLogLevels[i], level) == 0) {
@@ -568,16 +587,21 @@ void m4sensorhub_update_loglevels(char *tag, char *level,
break;
}
}
-
if ((tagindex == -1) || (levelindex == -1))
return;
+ logenableindex = tagindex/LOG_TAGS_PER_ENABLE;
+
/*Clear the revelant bits*/
- mask = 0x03;
- *log_levels &= ~(mask << (tagindex * 2));
+ mask = LOG_TAG_MASK;
+ *(log_level+logenableindex) &= ~(mask << ((tagindex % en) * b));
/*set debug level for the relevant bits*/
- *log_levels |= (levelindex << (tagindex * 2));
- KDEBUG(M4SH_INFO, "New M4 log levels = 0x%llx\n", *log_levels);
+ *(log_level+logenableindex) |= (levelindex << ((tagindex % en) * b));
+
+ KDEBUG(M4SH_DEBUG, "New M4 log levels = ");
+ for (i = 0; i < LOG_EN_SIZE; i++)
+ KDEBUG(M4SH_DEBUG, "enable %d = 0x%08x ", i, *(log_level+i));
+ KDEBUG(M4SH_DEBUG, "\n");
}
/* Usage: adb shell into the directory of sysinterface log_level and
@@ -585,25 +609,29 @@ void m4sensorhub_update_loglevels(char *tag, char *level,
static ssize_t m4sensorhub_set_loglevel(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned long long cur_loglevels;
+ uint32_t cur_loglevels[LOG_EN_SIZE];
char *tag, *level;
char **logbuf = (char **) &buf;
m4sensorhub_reg_read(&m4sensorhub_misc_data,
- M4SH_REG_LOG_LOGENABLE, (char *)&cur_loglevels);
+ M4SH_REG_LOG_LOGENABLE, (char *)cur_loglevels);
+
while (1) {
tag = strsep(logbuf, "=,\n ");
- if (tag == NULL)
+ if ((tag == NULL) || (logbuf == NULL))
break;
level = strsep(logbuf, "=,\n ");
- if (level == NULL)
+ if ((level == NULL) || (logbuf == NULL))
break;
- m4sensorhub_update_loglevels(tag, level, &cur_loglevels);
+ m4sensorhub_update_loglevels(tag, level,
+ (uint32_t *)cur_loglevels);
}
- return m4sensorhub_reg_write(&m4sensorhub_misc_data,
- M4SH_REG_LOG_LOGENABLE, (char *)&cur_loglevels,
- m4sh_no_mask);
+ m4sensorhub_reg_write(&m4sensorhub_misc_data,
+ M4SH_REG_LOG_LOGENABLE, (char *)cur_loglevels,
+ m4sh_no_mask);
+
+ return count;
}
static DEVICE_ATTR(log_level, S_IRUSR|S_IWUSR, m4sensorhub_get_loglevel,
diff --git a/drivers/mfd/m4sensorhub-extern.c b/drivers/mfd/m4sensorhub-extern.c
new file mode 100644
index 00000000000..771dc5cc4f3
--- /dev/null
+++ b/drivers/mfd/m4sensorhub-extern.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014 Motorola, Inc.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Adds ability to program periodic interrupts from user space that
+ * can wake the phone out of low power modes.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/m4sensorhub.h>
+#include <linux/slab.h>
+
+#define m4ext_err(format, args...) KDEBUG(M4SH_ERROR, format, ## args)
+
+struct m4sensorhub_data *m4ext_m4;
+DEFINE_MUTEX(m4ext_mutex);
+uint8_t m4ext_display_status;
+uint8_t m4ext_audio_status;
+
+static void m4ext_panic_callback(struct m4sensorhub_data *m4, void *context)
+{
+ int err;
+
+ mutex_lock(&m4ext_mutex);
+
+ if (m4ext_m4 == NULL) {
+ m4ext_err("%s: M4 data is NULL.\n", __func__);
+ err = -ENODATA;
+ goto m4ext_panic_callback_fail;
+ }
+
+ err = m4sensorhub_reg_write(m4, M4SH_REG_USERSETTINGS_SCREENSTATUS,
+ (char *)&m4ext_display_status, m4sh_no_mask);
+ if (err < 0)
+ m4ext_err("%s: Screen status write failed (%d).\n",
+ __func__, err);
+ else if (err != 1)
+ m4ext_err("%s: Screen status wrote %d bytes instead of 1.\n",
+ __func__, err);
+
+ err = m4sensorhub_reg_write(m4, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
+ (char *)&m4ext_audio_status, m4sh_no_mask);
+ if (err < 0)
+ m4ext_err("%s: Audio status write failed (%d).\n",
+ __func__, err);
+ else if (err != 1)
+ m4ext_err("%s: Audio status wrote %d bytes instead of 1.\n",
+ __func__, err);
+
+m4ext_panic_callback_fail:
+ mutex_unlock(&m4ext_mutex);
+ return;
+}
+
+int m4sensorhub_extern_init(struct m4sensorhub_data *m4)
+{
+ int err;
+
+ mutex_lock(&m4ext_mutex);
+
+ err = m4sensorhub_panic_register(m4, PANICHDL_EXTERN_RESTORE,
+ m4ext_panic_callback, NULL);
+ if (err < 0) {
+ m4ext_err("%s: Failed to register panic callback.\n", __func__);
+ goto m4sensorhub_extern_init_fail;
+ }
+
+ m4ext_m4 = m4;
+
+m4sensorhub_extern_init_fail:
+ mutex_unlock(&m4ext_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_extern_init);
+
+int m4sensorhub_extern_set_display_status(uint8_t status)
+{
+ int err;
+
+ mutex_lock(&m4ext_mutex);
+
+ if (m4ext_m4 == NULL) {
+ m4ext_err("%s: M4 data is NULL.\n", __func__);
+ err = -ENODATA;
+ goto m4sensorhub_extern_set_display_status_fail;
+ }
+
+ m4ext_display_status = status;
+
+ err = m4sensorhub_reg_write(m4ext_m4,
+ M4SH_REG_USERSETTINGS_SCREENSTATUS,
+ (char *)&status, m4sh_no_mask);
+ if (err < 0) {
+ m4ext_err("%s: I2C write failed (%d).\n", __func__, err);
+ goto m4sensorhub_extern_set_display_status_fail;
+ } else if (err != 1) {
+ m4ext_err("%s: Wrote %d bytes instead of 1.\n", __func__, err);
+ err = -EINVAL;
+ goto m4sensorhub_extern_set_display_status_fail;
+ }
+
+ err = 0;
+
+m4sensorhub_extern_set_display_status_fail:
+ mutex_unlock(&m4ext_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_extern_set_display_status);
+
+int m4sensorhub_extern_set_audio_status(uint8_t status)
+{
+ int err;
+
+ mutex_lock(&m4ext_mutex);
+
+ if (m4ext_m4 == NULL) {
+ m4ext_err("%s: M4 data is NULL.\n", __func__);
+ err = -ENODATA;
+ goto m4sensorhub_extern_set_audio_status_fail;
+ }
+
+ m4ext_audio_status = status;
+
+ err = m4sensorhub_reg_write(m4ext_m4,
+ M4SH_REG_USERSETTINGS_AUDIOSTATUS,
+ (char *)&status, m4sh_no_mask);
+ if (err < 0) {
+ m4ext_err("%s: I2C write failed (%d).\n", __func__, err);
+ goto m4sensorhub_extern_set_audio_status_fail;
+ } else if (err != 1) {
+ m4ext_err("%s: Wrote %d bytes instead of 1.\n", __func__, err);
+ err = -EINVAL;
+ goto m4sensorhub_extern_set_audio_status_fail;
+ }
+
+ err = 0;
+
+m4sensorhub_extern_set_audio_status_fail:
+ mutex_unlock(&m4ext_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_extern_set_audio_status);
diff --git a/drivers/mfd/m4sensorhub-panic.c b/drivers/mfd/m4sensorhub-panic.c
index b127adeba5c..34ad6658453 100644
--- a/drivers/mfd/m4sensorhub-panic.c
+++ b/drivers/mfd/m4sensorhub-panic.c
@@ -40,6 +40,7 @@ static const char *callback_name[PANICHDL_MAX] = {
[PANICHDL_FUSION_RESTORE] = "fusion_restore",
[PANICHDL_MPU9150_RESTORE] = "mpu9150_restore",
[PANICHDL_PEDOMETER_RESTORE] = "pedometer_restore",
+ [PANICHDL_EXTERN_RESTORE] = "extern_restore",
};
struct m4sensorhub_panic_callback {
diff --git a/drivers/mfd/m4sensorhub-reg.h b/drivers/mfd/m4sensorhub-reg.h
index 96719a08927..753ea9a8846 100644
--- a/drivers/mfd/m4sensorhub-reg.h
+++ b/drivers/mfd/m4sensorhub-reg.h
@@ -87,9 +87,9 @@ static const struct {
[M4SH_REG_FUSION_LOCALX] = {M4SH_TYPE_FUSION, 0x10, 4},
[M4SH_REG_FUSION_LOCALY] = {M4SH_TYPE_FUSION, 0x14, 4},
[M4SH_REG_FUSION_LOCALZ] = {M4SH_TYPE_FUSION, 0x18, 4},
- [M4SH_REG_FUSION_WORLDX] = {M4SH_TYPE_FUSION, 0x1c, 4},
- [M4SH_REG_FUSION_WORLDY] = {M4SH_TYPE_FUSION, 0x20, 4},
- [M4SH_REG_FUSION_WORLDZ] = {M4SH_TYPE_FUSION, 0x24, 4},
+ [M4SH_REG_FUSION_GRAVITYX] = {M4SH_TYPE_FUSION, 0x1c, 4},
+ [M4SH_REG_FUSION_GRAVITYY] = {M4SH_TYPE_FUSION, 0x20, 4},
+ [M4SH_REG_FUSION_GRAVITYZ] = {M4SH_TYPE_FUSION, 0x24, 4},
[M4SH_REG_FUSION_ROTATIONVECTOR] = {M4SH_TYPE_FUSION, 0x28, 16},
[M4SH_REG_FUSION_HEADING] = {M4SH_TYPE_FUSION, 0x38, 2},
[M4SH_REG_FUSION_HEADING_ACCURACY] = {M4SH_TYPE_FUSION, 0x3a, 1},
@@ -112,6 +112,8 @@ static const struct {
[M4SH_REG_METS_METS] = {M4SH_TYPE_METS, 0x4, 4},
[M4SH_REG_METS_CALORIES] = {M4SH_TYPE_METS, 0x8, 4},
[M4SH_REG_METS_HEALTHYMINUTES] = {M4SH_TYPE_METS, 0xc, 4},
+ [M4SH_REG_METS_METS_NO_RMR] = {M4SH_TYPE_METS, 0x10, 4},
+ [M4SH_REG_METS_CALORIES_NO_RMR] = {M4SH_TYPE_METS, 0x14, 4},
[M4SH_REG_USERSETTINGS_SCREENSTATUS] = {M4SH_TYPE_USERSETTINGS, 0x0, 1},
[M4SH_REG_USERSETTINGS_USERAGE] = {M4SH_TYPE_USERSETTINGS, 0x1, 1},
[M4SH_REG_USERSETTINGS_USERGENDER] = {M4SH_TYPE_USERSETTINGS, 0x2, 1},
@@ -205,7 +207,7 @@ static const unsigned int bank_size_tbl[M4SH_TYPE__NUM] = {
[M4SH_TYPE_FUSION] = 59,
[M4SH_TYPE_COMPASS] = 17,
[M4SH_TYPE_GYRO] = 16,
- [M4SH_TYPE_METS] = 16,
+ [M4SH_TYPE_METS] = 24,
[M4SH_TYPE_USERSETTINGS] = 8,
[M4SH_TYPE_POWER] = 9,
[M4SH_TYPE_LOCATION] = 14,
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 5b96da5fda8..5aed79aa3c4 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -586,6 +586,13 @@ config WAKEUP_SOURCE_NOTIFY
help
Driver to allow early notification of wakeups
+config ALS_WHILE_CHARGING
+ tristate "use ALS when on charger"
+ depends on WAKEUP_SOURCE_NOTIFY
+ help
+ ALS when unit is on charger
+
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2f57dbac599..39d1e04e896 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_MOT_UTAG) += utag/
obj-$(CONFIG_BQ5105X_CTRL) += bq5105x_ctrl.o
obj-$(CONFIG_BQ5105X_DETECT) += bq5105x_detect.o
obj-$(CONFIG_WAKEUP_SOURCE_NOTIFY) += wakeup_source_notify.o
+obj-$(CONFIG_WAKEUP_SOURCE_NOTIFY) += als_notify.o
diff --git a/drivers/misc/als_notify.c b/drivers/misc/als_notify.c
new file mode 100644
index 00000000000..cbb4f3a55cd
--- /dev/null
+++ b/drivers/misc/als_notify.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Motorola Mobility LLC.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/notifier.h>
+#include <linux/als_notify.h>
+
+static BLOCKING_NOTIFIER_HEAD(als_notifier_list);
+
+/**
+ * als_register_notify - register a notifier callback for triggering display init
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ */
+void als_register_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_register(&als_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(als_register_notify);
+
+/**
+ * als_unregister_notify - unregister a notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * als_register_notify() must have been previously called
+ * for this function to work properly.
+ */
+void als_unregister_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&als_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(als_unregister_notify);
+
+void als_notify_subscriber(unsigned long event)
+{
+ blocking_notifier_call_chain(&als_notifier_list, event, NULL);
+}
+EXPORT_SYMBOL_GPL(als_notify_subscriber);
diff --git a/drivers/misc/c55_ctrl.c b/drivers/misc/c55_ctrl.c
index 54ffc6e5b2b..cf763272922 100644
--- a/drivers/misc/c55_ctrl.c
+++ b/drivers/misc/c55_ctrl.c
@@ -143,7 +143,6 @@ static ssize_t c55_ctrl_enable(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct c55_ctrl_data *cdata = dev_get_drvdata(dev);
- struct m4sensorhub_data *m4sensorhub = m4sensorhub_client_get_drvdata();
int mode;
if (kstrtoint(buf, 10, &mode) < 0)
@@ -154,7 +153,7 @@ static ssize_t c55_ctrl_enable(struct device *dev,
return -EINVAL;
}
- if (m4sensorhub->mode != NORMALMODE) {
+ if (m4sensorhub_get_current_mode() != NORMALMODE) {
dev_err(dev, "M4 not ready, Unable to set screen status\n");
return -EINVAL;
}
@@ -169,9 +168,7 @@ static ssize_t c55_ctrl_enable(struct device *dev,
gpio_set_value(cdata->ap_c55_int_gpio, 1);
- if (m4sensorhub_reg_write_1byte
- (m4sensorhub, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
- AUDIO_STATUS_ON, 0xFF) != 1) {
+ if (m4sensorhub_extern_set_audio_status(AUDIO_STATUS_ON) < 0) {
dev_err(dev, "Unable to set screen status to 0x01\n");
mutex_unlock(&cdata->ctrl_mutex);
return -EINVAL;
@@ -189,9 +186,7 @@ static ssize_t c55_ctrl_enable(struct device *dev,
cdata->c55_ap_int_enabled = 0;
}
- if (m4sensorhub_reg_write_1byte
- (m4sensorhub, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
- AUDIO_STATUS_OFF, 0xFF) != 1) {
+ if (m4sensorhub_extern_set_audio_status(AUDIO_STATUS_OFF) < 0) {
dev_err(dev, "Unable to set screen status to 0x00\n");
mutex_unlock(&cdata->ctrl_mutex);
return -EINVAL;
@@ -363,7 +358,6 @@ static int c55_ctrl_remove(struct platform_device *pdev)
static int c55_ctrl_suspend(struct platform_device *dev, pm_message_t state)
{
struct c55_ctrl_data *cdata = dev_get_drvdata(&dev->dev);
- struct m4sensorhub_data *m4sensorhub = m4sensorhub_client_get_drvdata();
if (cdata->c55_mode != C55_OFF) {
dev_warn(&dev->dev, "C55 still ON when going into suspend\n");
@@ -375,9 +369,7 @@ static int c55_ctrl_suspend(struct platform_device *dev, pm_message_t state)
cdata->c55_ap_int_enabled = 0;
}
- if (m4sensorhub_reg_write_1byte
- (m4sensorhub, M4SH_REG_USERSETTINGS_AUDIOSTATUS,
- AUDIO_STATUS_OFF, 0xFF) != 1) {
+ if (m4sensorhub_extern_set_audio_status(AUDIO_STATUS_OFF) < 0) {
dev_err(&dev->dev,
"Unable to set screen status to 0x00\n");
}
diff --git a/drivers/misc/m4sensorhub_als.c b/drivers/misc/m4sensorhub_als.c
index 3f61edefff2..6445d9f0181 100644
--- a/drivers/misc/m4sensorhub_als.c
+++ b/drivers/misc/m4sensorhub_als.c
@@ -28,12 +28,21 @@
#include <linux/m4sensorhub.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/delay.h>
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+#include <linux/notifier.h>
+#include <linux/als_notify.h>
+#ifdef CONFIG_ALS_WHILE_CHARGING
+#include <linux/wakeup_source_notify.h>
+#endif /* CONFIG_ALS_WHILE_CHARGING */
+#endif
#define m4als_err(format, args...) KDEBUG(M4SH_ERROR, format, ## args)
#define M4ALS_DRIVER_NAME "m4sensorhub_als"
#define M4ALS_IRQ_ENABLED_BIT 0
+#define ALS_SAMPLERATE_WHILE_DOCKED 10 /* in seconds */
struct m4als_driver_data {
struct platform_device *pdev;
@@ -42,13 +51,39 @@ struct m4als_driver_data {
struct input_dev *indev;
struct delayed_work m4als_work;
+ /* Beware of changing this from uint16, check als_notify.h
+ since notifier uses values outside luminosity range for
+ conveying enable/disable status */
uint16_t luminosity;
int16_t samplerate;
int16_t latest_samplerate;
int16_t fastest_rate;
uint16_t status;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ struct notifier_block charger_nb;
+ bool chargerstatus;
+#endif
};
+#ifdef CONFIG_ALS_WHILE_CHARGING
+static int charger_notify(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ struct m4als_driver_data *dd =
+ container_of(self, struct m4als_driver_data, charger_nb);
+ switch (action) {
+ case DISPLAY_WAKE_EVENT_DOCKON:
+ case DISPLAY_WAKE_EVENT_DOCKOFF:
+ dd->chargerstatus = (action == DISPLAY_WAKE_EVENT_DOCKON);
+ pr_info("%s: dd->chargerstatus is %d\n",
+ __func__, dd->chargerstatus);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+#endif
+
static void m4als_work_func(struct work_struct *work)
{
int err = 0;
@@ -81,8 +116,18 @@ static void m4als_work_func(struct work_struct *work)
dd->luminosity = luminosity;
- input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
- input_sync(dd->indev);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (dd->chargerstatus == true) {
+ als_notify_subscriber(luminosity);
+ } else {
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+ }
+#else
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+#endif
+
if (dd->samplerate > 0)
queue_delayed_work(system_freezable_wq, &(dd->m4als_work),
msecs_to_jiffies(dd->samplerate));
@@ -101,6 +146,12 @@ static int m4als_set_samplerate(struct m4als_driver_data *dd, int16_t rate)
int err = 0;
int size = 0;
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ if (rate == -1 && dd->chargerstatus == true) {
+ rate = ALS_SAMPLERATE_WHILE_DOCKED * 1000;
+ }
+#endif
+
if ((rate >= 0) && (rate <= dd->fastest_rate))
rate = dd->fastest_rate;
@@ -132,9 +183,17 @@ static int m4als_set_samplerate(struct m4als_driver_data *dd, int16_t rate)
}
cancel_delayed_work(&(dd->m4als_work));
dd->samplerate = rate;
- if (dd->samplerate > 0)
+ if (dd->samplerate > 0) {
queue_delayed_work(system_freezable_wq, &(dd->m4als_work),
msecs_to_jiffies(rate));
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ als_notify_subscriber(ALS_ENABLED);
+#endif
+ } else {
+#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+ als_notify_subscriber(ALS_DISABLED);
+#endif
+ }
m4als_set_samplerate_fail:
return err;
@@ -153,6 +212,8 @@ static ssize_t m4als_setrate_store(struct device *dev,
int err = 0;
struct m4als_driver_data *dd = dev_get_drvdata(dev);
int value = 0;
+ int regsize = 0;
+ uint16_t luminosity = 0;
mutex_lock(&(dd->mutex));
@@ -175,6 +236,32 @@ static ssize_t m4als_setrate_store(struct device *dev,
goto m4als_enable_store_exit;
}
+ /* Read and send raw value for gesture wakeup */
+ msleep(120);
+ regsize = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_LIGHTSENSOR_SIGNAL);
+ if (regsize < 0) {
+ m4als_err("%s: Reading from invalid register %d.\n",
+ __func__, regsize);
+ err = regsize;
+ goto m4als_enable_store_exit;
+ }
+
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_LIGHTSENSOR_SIGNAL,
+ (char *)&luminosity);
+ if (err < 0) {
+ m4als_err("%s: Failed to read luminosity data.\n", __func__);
+ goto m4als_enable_store_exit;
+ } else if (err != regsize) {
+ m4als_err("%s: Read %d bytes instead of %d.\n",
+ __func__, err, regsize);
+ goto m4als_enable_store_exit;
+ }
+
+ dd->luminosity = luminosity;
+
+ input_event(dd->indev, EV_MSC, MSC_RAW, dd->luminosity);
+ input_sync(dd->indev);
+
m4als_enable_store_exit:
if (err < 0)
m4als_err("%s: Failed with error code %d.\n", __func__, err);
@@ -304,12 +391,6 @@ static int m4als_driver_init(struct init_calldata *p_arg)
goto m4als_driver_init_fail;
}
- err = m4als_create_sysfs(dd);
- if (err < 0) {
- m4als_err("%s: Failed to create sysfs.\n", __func__);
- goto m4als_driver_init_sysfs_fail;
- }
-
INIT_DELAYED_WORK(&(dd->m4als_work), m4als_work_func);
err = m4sensorhub_panic_register(dd->m4, PANICHDL_ALS_RESTORE,
@@ -318,8 +399,6 @@ static int m4als_driver_init(struct init_calldata *p_arg)
KDEBUG(M4SH_ERROR, "Als panic callback register failed\n");
goto m4als_driver_init_exit;
-m4als_driver_init_sysfs_fail:
- input_unregister_device(dd->indev);
m4als_driver_init_fail:
m4als_err("%s: Init failed with error code %d.\n", __func__, err);
m4als_driver_init_exit:
@@ -359,8 +438,22 @@ static int m4als_probe(struct platform_device *pdev)
goto m4als_probe_fail;
}
+ err = m4als_create_sysfs(dd);
+ if (err < 0) {
+ m4als_err("%s: Failed to create sysfs.\n", __func__);
+ goto m4als_driver_init_sysfs_fail;
+ }
+
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ dd->chargerstatus = false;
+ dd->charger_nb.notifier_call = charger_notify;
+ wakeup_source_register_notify(&dd->charger_nb);
+#endif
+
return 0;
+m4als_driver_init_sysfs_fail:
+ m4sensorhub_unregister_initcall(m4als_driver_init);
m4als_probe_fail:
mutex_destroy(&(dd->mutex));
kfree(dd);
@@ -377,6 +470,9 @@ static int __exit m4als_remove(struct platform_device *pdev)
cancel_delayed_work(&(dd->m4als_work));
m4als_remove_sysfs(dd);
m4sensorhub_unregister_initcall(m4als_driver_init);
+#ifdef CONFIG_ALS_WHILE_CHARGING
+ wakeup_source_unregister_notify(&dd->charger_nb);
+#endif
if (dd->indev != NULL)
input_unregister_device(dd->indev);
mutex_destroy(&(dd->mutex));
diff --git a/drivers/misc/m4sensorhub_fusion.c b/drivers/misc/m4sensorhub_fusion.c
index e1330f56263..816b89bea39 100644
--- a/drivers/misc/m4sensorhub_fusion.c
+++ b/drivers/misc/m4sensorhub_fusion.c
@@ -126,6 +126,90 @@ static void m4fus_work_func(struct work_struct *work)
dd->iiodat[1].type = FUSION_TYPE_ORIENTATION;
dd->iiodat[1].timestamp = iio_get_time_ns();
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_GRAVITYX);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_GRAVITYX,
+ (char *)&(dd->iiodat[2].values[0]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read gravityX data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "gravityX");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_GRAVITYY);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_GRAVITYY,
+ (char *)&(dd->iiodat[2].values[1]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read gravityY data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "gravityY");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_GRAVITYZ);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_GRAVITYZ,
+ (char *)&(dd->iiodat[2].values[2]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read gravityZ data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "gravityZ");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ dd->iiodat[2].type = FUSION_TYPE_GRAVITY;
+ dd->iiodat[2].timestamp = iio_get_time_ns();
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_LOCALX);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_LOCALX,
+ (char *)&(dd->iiodat[3].values[0]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read localX data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "localX");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_LOCALY);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_LOCALY,
+ (char *)&(dd->iiodat[3].values[1]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read localY data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "localY");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_FUSION_LOCALZ);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_FUSION_LOCALZ,
+ (char *)&(dd->iiodat[3].values[2]));
+ if (err < 0) {
+ m4fus_err("%s: Failed to read localZ data.\n", __func__);
+ goto m4fus_isr_fail;
+ } else if (err != size) {
+ m4fus_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "localZ");
+ err = -EBADE;
+ goto m4fus_isr_fail;
+ }
+
+ dd->iiodat[3].type = FUSION_TYPE_LINEAR_ACCELERATION;
+ dd->iiodat[3].timestamp = iio_get_time_ns();
+
/*
* For some reason, IIO knows we are sending an array,
* so all FUSION_TYPE_* indicies will be sent
diff --git a/drivers/misc/m4sensorhub_gesture.c b/drivers/misc/m4sensorhub_gesture.c
index d5e364ea6c5..9ccbbe3091e 100644
--- a/drivers/misc/m4sensorhub_gesture.c
+++ b/drivers/misc/m4sensorhub_gesture.c
@@ -114,7 +114,7 @@ static void m4ges_isr(enum m4sensorhub_irqs int_event, void *handle)
/* the GESTURE_VIEW is only effect for kernel now
* do not send gesture to android
*/
- goto m4ges_isr_fail;
+ goto m4ges_no_iio_push;
}
#endif /* CONFIG_WAKEUP_SOURCE_NOTIFY */
@@ -122,6 +122,12 @@ static void m4ges_isr(enum m4sensorhub_irqs int_event, void *handle)
iio_push_to_buffers(iio, (unsigned char *)&(dd->iiodat));
dd->gesture_count++;
+m4ges_no_iio_push:
+ /* Log gestures received */
+ pr_info("%s: Gesture received: count=%u, type=%hhu, value=%hhd.\n",
+ __func__, dd->gesture_count, dd->iiodat.gesture_type,
+ dd->iiodat.gesture_value);
+
m4ges_isr_fail:
if (err < 0)
m4ges_err("%s: Failed with error code %d.\n", __func__, err);
diff --git a/drivers/misc/m4sensorhub_mpu9150.c b/drivers/misc/m4sensorhub_mpu9150.c
index a2411c27d4f..55d160bc607 100644
--- a/drivers/misc/m4sensorhub_mpu9150.c
+++ b/drivers/misc/m4sensorhub_mpu9150.c
@@ -79,8 +79,6 @@ struct mpu9150_client {
struct mutex mutex; /* prevent concurrent thread access */
struct delayed_work mpu9150_work[NUM_TYPES];
signed short fastest_rate[NUM_TYPES];
- int calibration_done;
- int app_override;
};
struct mpu9150_client *misc_mpu9150_data;
@@ -142,23 +140,6 @@ static void m4_report_mpu9150_inputevent(
}
}
-static void m4_queue_delayed_work(struct mpu9150_client *dd,
- int delay, enum mpu9150_sensor type)
-{
- if (type == TYPE_COMPASS) {
- /* initial calibration is not done and there is
- no app requesting compass data */
- if ((!dd->calibration_done) && (!dd->app_override))
- /* For current drain saving, m4 is sampling
- compass at 40ms while omap is polling
- for compass data at 15 secs */
- delay = 15000;
- }
- queue_delayed_work(system_freezable_wq,
- &(dd->mpu9150_work[type]),
- msecs_to_jiffies(delay));
-}
-
static void m4_set_mpu9150_delay(struct mpu9150_client *mpu9150_client_data,
int delay, enum mpu9150_sensor type)
{
@@ -197,18 +178,19 @@ static void m4_set_mpu9150_delay(struct mpu9150_client *mpu9150_client_data,
cancel_delayed_work(&(dd->mpu9150_work[type]));
dd->samplerate[type] = delay;
if (dd->samplerate[type] > 0)
- m4_queue_delayed_work(dd, delay, type);
+ queue_delayed_work(system_freezable_wq,
+ &(dd->mpu9150_work[type]),
+ msecs_to_jiffies(delay));
+
}
}
-
static void m4_read_mpu9150_data(struct mpu9150_client *mpu9150_client_data,
enum mpu9150_sensor type)
{
sCompassData compassdata;
sAccelData acceldata;
sGyroData gyrodata;
- struct mpu9150_client *dd = mpu9150_client_data;
switch (type) {
case TYPE_GYRO:
@@ -249,18 +231,6 @@ static void m4_read_mpu9150_data(struct mpu9150_client *mpu9150_client_data,
mpu9150_client_data->compass_data.cz = compassdata.z;
mpu9150_client_data->compass_data.ca = compassdata.accuracy;
- /* Check if calibration is complete */
- if ((!(dd->calibration_done)) && (compassdata.accuracy)) {
- dd->calibration_done = 1;
- KDEBUG(M4SH_INFO, "Calibration complete\n");
- /* Stop compass sampling if no app is using the data */
- if (dd->app_override == 0) {
- m4_set_mpu9150_delay(dd,
- -1,
- TYPE_COMPASS);
- KDEBUG(M4SH_INFO, "Init cal done. Turning off compass");
- }
- }
break;
default:
@@ -320,7 +290,9 @@ static void m4compass_work_func(struct work_struct *work)
m4_report_mpu9150_inputevent(dd, TYPE_COMPASS);
rate = dd->samplerate[TYPE_COMPASS];
if (rate > 0)
- m4_queue_delayed_work(dd, rate, TYPE_COMPASS);
+ queue_delayed_work(system_freezable_wq,
+ &(dd->mpu9150_work[TYPE_COMPASS]),
+ msecs_to_jiffies(rate));
mutex_unlock(&(dd->mutex));
}
@@ -407,20 +379,8 @@ static ssize_t m4_mpu9150_write_compass_setdelay(struct device *dev,
mutex_lock(&(misc_mpu9150_data->mutex));
- if (misc_mpu9150_data->calibration_done == 0) {
- /* If calibration is not complete and app tries to
- turn off ignore */
- if (scanresult < 0) {
- misc_mpu9150_data->app_override = 0;
- goto compass_setdelay_exit;
- } else {
- misc_mpu9150_data->app_override = 1;
- }
- }
m4_set_mpu9150_delay(misc_mpu9150_data, scanresult, TYPE_COMPASS);
-compass_setdelay_exit:
-
mutex_unlock(&(misc_mpu9150_data->mutex));
return count;
@@ -611,7 +571,9 @@ static void mpu9150_panic_restore(struct m4sensorhub_data *m4sensorhub,
m4_set_mpu9150_delay(dd, rate, type);
cancel_delayed_work(&(dd->mpu9150_work[type]));
if (rate > 0)
- m4_queue_delayed_work(dd, rate, type);
+ queue_delayed_work(system_freezable_wq,
+ &(dd->mpu9150_work[type]),
+ msecs_to_jiffies(rate));
}
mutex_unlock(&(dd->mutex));
}
@@ -633,9 +595,7 @@ static int mpu9150_driver_init(struct init_calldata *p_arg)
dd);
if (ret < 0)
KDEBUG(M4SH_ERROR, "HR panic callback register failed\n");
- m4_set_mpu9150_delay(dd,
- 40,
- TYPE_COMPASS);
+
mutex_unlock(&(dd->mutex));
return ret;
}
@@ -668,8 +628,6 @@ static int mpu9150_client_probe(struct platform_device *pdev)
mpu9150_client_data->fastest_rate[TYPE_ACCEL] = 40;
mpu9150_client_data->fastest_rate[TYPE_GYRO] = 40;
mpu9150_client_data->fastest_rate[TYPE_COMPASS] = 40;
- mpu9150_client_data->calibration_done = 0;
- mpu9150_client_data->app_override = 0;
mpu9150_client_data->input_dev = input_allocate_device();
if (!mpu9150_client_data->input_dev) {
diff --git a/drivers/misc/m4sensorhub_pedometer.c b/drivers/misc/m4sensorhub_pedometer.c
index cf326454bea..0be14698e1d 100644
--- a/drivers/misc/m4sensorhub_pedometer.c
+++ b/drivers/misc/m4sensorhub_pedometer.c
@@ -40,6 +40,8 @@
#define M4PED_IRQ_ENABLED_BIT 0
#define M4PED_FEATURE_ENABLED_BIT 1
+#define M4PED_USERDATA_SIZE 5
+
struct m4ped_driver_data {
struct platform_device *pdev;
struct m4sensorhub_data *m4;
@@ -47,9 +49,12 @@ struct m4ped_driver_data {
struct m4sensorhub_pedometer_iio_data iiodat;
struct m4sensorhub_pedometer_iio_data base_dat;
- struct delayed_work m4ped_work;
+ struct m4sensorhub_pedometer_iio_data last_dat;
+ struct delayed_work m4ped_work;
+
int16_t samplerate;
int16_t fastest_rate;
+ uint8_t userdata[M4PED_USERDATA_SIZE];
uint16_t status;
};
@@ -57,6 +62,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
struct m4ped_driver_data *dd)
{
int err = 0, size = 0;
+ struct m4sensorhub_pedometer_iio_data dat;
/*input validations */
if ((iio == NULL) || (dd == NULL)) {
@@ -80,7 +86,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4,
M4SH_REG_PEDOMETER_TOTALDISTANCE);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_PEDOMETER_TOTALDISTANCE,
- (char *)&(dd->iiodat.total_distance));
+ (char *)&(dat.total_distance));
if (err < 0) {
m4ped_err("%s: Failed to read total_distance data.\n",
__func__);
@@ -94,7 +100,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_PEDOMETER_TOTALSTEPS);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_PEDOMETER_TOTALSTEPS,
- (char *)&(dd->iiodat.total_steps));
+ (char *)&(dat.total_steps));
if (err < 0) {
m4ped_err("%s: Failed to read total_steps data.\n", __func__);
goto m4ped_read_fail;
@@ -121,7 +127,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_METS_HEALTHYMINUTES);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_METS_HEALTHYMINUTES,
- (char *)&(dd->iiodat.healthy_minutes));
+ (char *)&(dat.healthy_minutes));
if (err < 0) {
m4ped_err("%s: Failed to read healthy_minutes data.\n",
__func__);
@@ -135,7 +141,7 @@ static int m4ped_read_report_data(struct iio_dev *iio,
size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_METS_CALORIES);
err = m4sensorhub_reg_read(dd->m4, M4SH_REG_METS_CALORIES,
- (char *)&(dd->iiodat.calories));
+ (char *)&(dat.calories));
if (err < 0) {
m4ped_err("%s: Failed to read calories data.\n", __func__);
goto m4ped_read_fail;
@@ -146,12 +152,63 @@ static int m4ped_read_report_data(struct iio_dev *iio,
goto m4ped_read_fail;
}
+ size = m4sensorhub_reg_getsize(dd->m4, M4SH_REG_METS_CALORIES_NO_RMR);
+ err = m4sensorhub_reg_read(dd->m4, M4SH_REG_METS_CALORIES_NO_RMR,
+ (char *)&(dat.calories_normr));
+ if (err < 0) {
+ m4ped_err("%s: Failed to read calories_normr data.\n",
+ __func__);
+ goto m4ped_read_fail;
+ } else if (err != size) {
+ m4ped_err("%s: Read %d bytes instead of %d for %s.\n",
+ __func__, err, size, "calories_normr");
+ err = -EBADE;
+ goto m4ped_read_fail;
+ }
+
dd->iiodat.timestamp = iio_get_time_ns();
- dd->iiodat.total_distance += dd->base_dat.total_distance;
- dd->iiodat.total_steps += dd->base_dat.total_steps;
- dd->iiodat.healthy_minutes += dd->base_dat.healthy_minutes;
- dd->iiodat.calories += dd->base_dat.calories;
+ /* Save data if these values decrease (they monotonically increase) */
+ if ((dat.total_distance < dd->last_dat.total_distance) ||
+ (dat.total_steps < dd->last_dat.total_steps) ||
+ (dat.healthy_minutes < dd->last_dat.healthy_minutes) ||
+ (dat.calories < dd->last_dat.calories) ||
+ (dat.calories_normr < dd->last_dat.calories_normr)) {
+ m4ped_err("%s: Error: Current = %u %u %u %u %u "
+ "Last = %u %u %u %u %u, Base = %u %u %u %u %u\n",
+ __func__, dat.total_distance,
+ dat.total_steps, dat.healthy_minutes,
+ dat.calories, dat.calories_normr,
+ dd->last_dat.total_distance,
+ dd->last_dat.total_steps,
+ dd->last_dat.healthy_minutes, dd->last_dat.calories,
+ dd->last_dat.calories_normr,
+ dd->base_dat.total_distance,
+ dd->base_dat.total_steps,
+ dd->base_dat.healthy_minutes, dd->base_dat.calories,
+ dd->base_dat.calories_normr);
+ m4ped_err("%s: iio = %u %u %u %u %u\n", __func__,
+ dd->iiodat.total_distance,
+ dd->iiodat.total_steps,
+ dd->iiodat.healthy_minutes, dd->iiodat.calories,
+ dd->iiodat.calories_normr);
+ goto m4ped_read_fail;
+ }
+
+ dd->last_dat.total_distance = dat.total_distance;
+ dd->last_dat.total_steps = dat.total_steps;
+ dd->last_dat.healthy_minutes = dat.healthy_minutes;
+ dd->last_dat.calories = dat.calories;
+ dd->last_dat.calories_normr = dat.calories_normr;
+
+ dd->iiodat.total_distance = dat.total_distance +
+ dd->base_dat.total_distance;
+ dd->iiodat.total_steps = dat.total_steps + dd->base_dat.total_steps;
+ dd->iiodat.healthy_minutes = dat.healthy_minutes +
+ dd->base_dat.healthy_minutes;
+ dd->iiodat.calories = dat.calories + dd->base_dat.calories;
+ dd->iiodat.calories_normr = dat.calories_normr +
+ dd->base_dat.calories_normr;
iio_push_to_buffers(iio, (unsigned char *)&(dd->iiodat));
@@ -181,6 +238,42 @@ static void m4ped_work_func(struct work_struct *work)
return;
}
+static int m4ped_write_userdata(struct m4ped_driver_data *dd)
+{
+ int err;
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERAGE,
+ &(dd->userdata[0]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write age.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERGENDER,
+ &(dd->userdata[1]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write gender.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERHEIGHT,
+ &(dd->userdata[2]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write height.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+ err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERWEIGHT,
+ &(dd->userdata[3]), m4sh_no_mask);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write weight.\n", __func__);
+ goto m4ped_write_userdata_fail;
+ }
+
+m4ped_write_userdata_fail:
+ return err;
+}
+
static int m4ped_set_samplerate(struct iio_dev *iio, int16_t rate)
{
int err = 0;
@@ -278,13 +371,14 @@ static ssize_t m4ped_iiodata_show(struct device *dev,
mutex_lock(&(dd->mutex));
size = snprintf(buf, PAGE_SIZE,
- "%s%hhu\n%s%u\n%s%u\n%s%hu\n%s%u\n%s%u\n",
+ "%s%hhu\n%s%u\n%s%u\n%s%hu\n%s%u\n%s%u\n%s%u\n",
"ped_activity: ", dd->iiodat.ped_activity,
"total_distance: ", dd->iiodat.total_distance,
"total_steps: ", dd->iiodat.total_steps,
"current_speed: ", dd->iiodat.current_speed,
"healthy_minutes: ", dd->iiodat.healthy_minutes,
- "calories: ", dd->iiodat.calories);
+ "calories: ", dd->iiodat.calories,
+ "calories_normr: ", dd->iiodat.calories_normr);
mutex_unlock(&(dd->mutex));
return size;
}
@@ -298,11 +392,11 @@ static ssize_t m4ped_userdata_show(struct device *dev,
struct iio_dev *iio = platform_get_drvdata(pdev);
struct m4ped_driver_data *dd = iio_priv(iio);
ssize_t size = 0;
- uint8_t data[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t data[M4PED_USERDATA_SIZE] = {0x00};
mutex_lock(&(dd->mutex));
- err = m4sensorhub_reg_read_n(dd->m4, M4SH_REG_USERSETTINGS_SCREENSTATUS,
+ err = m4sensorhub_reg_read_n(dd->m4, M4SH_REG_USERSETTINGS_USERAGE,
(char *)&(data[0]), ARRAY_SIZE(data));
if (err < 0) {
m4ped_err("%s: Failed to read user data.\n", __func__);
@@ -315,11 +409,11 @@ static ssize_t m4ped_userdata_show(struct device *dev,
}
size = snprintf(buf, PAGE_SIZE,
- "%s%s\n%s%hhu\n%s%hhu\n%s%hhu\n",
- "Gender (M/F): ", data[2] ? "M" : "F",
- "Age (yrs): ", data[1],
- "Height (cm): ", data[3],
- "Weight (kg): ", data[4]);
+ "%s%s\n%s%hhu\n%s%hhu\n%s%hu\n",
+ "Gender (M/F): ", data[1] ? "M" : "F",
+ "Age (yrs): ", data[0],
+ "Height (cm): ", data[2],
+ "Weight (kg): ", data[3] | (data[4] << 8));
m4ped_userdata_show_fail:
mutex_unlock(&(dd->mutex));
@@ -334,6 +428,7 @@ m4ped_userdata_show_fail:
* Example:
* Female, 22, 168cm, 49kg
* 0x00,0x16,0xA7,0x31\n
+ * echo 0x00,0x16,0xA7,0x31 > userdata
*/
static ssize_t m4ped_userdata_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
@@ -344,7 +439,7 @@ static ssize_t m4ped_userdata_store(struct device *dev,
struct m4ped_driver_data *dd = iio_priv(iio);
unsigned int value = 0;
unsigned char convbuf[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char outbuf[4] = {0x00, 0x00, 0x00, 0x00};
+ unsigned char outbuf[M4PED_USERDATA_SIZE] = {0x00};
int i = 0;
mutex_lock(&(dd->mutex));
@@ -373,31 +468,16 @@ static ssize_t m4ped_userdata_store(struct device *dev,
outbuf[i] = (unsigned char) value;
}
- err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERAGE,
- &(outbuf[1]), m4sh_no_mask);
- if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
- goto m4ped_userdata_store_fail;
- }
+ for (i = 0; i < M4PED_USERDATA_SIZE; i++)
+ dd->userdata[i] = outbuf[i];
- err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERGENDER,
- &(outbuf[0]), m4sh_no_mask);
- if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
- goto m4ped_userdata_store_fail;
- }
-
- err = m4sensorhub_reg_write(dd->m4, M4SH_REG_USERSETTINGS_USERHEIGHT,
- &(outbuf[2]), m4sh_no_mask);
- if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
- goto m4ped_userdata_store_fail;
- }
+ dd->userdata[0] = outbuf[1]; /* Age */
+ dd->userdata[1] = outbuf[0]; /* Gender */
- err = m4sensorhub_reg_write_n(dd->m4, M4SH_REG_USERSETTINGS_USERWEIGHT,
- &(outbuf[3]), m4sh_no_mask, 1);
+ err = m4ped_write_userdata(dd);
if (err < 0) {
- m4ped_err("%s: Failed to write user data.\n", __func__);
+ m4ped_err("%s: Failed to write user data (%d).\n",
+ __func__, err);
goto m4ped_userdata_store_fail;
}
@@ -606,13 +686,12 @@ static void m4ped_panic_restore(struct m4sensorhub_data *m4sensorhub,
mutex_lock(&(dd->mutex));
- dd->base_dat.total_distance = dd->iiodat.total_distance;
- dd->base_dat.total_steps = dd->iiodat.total_steps;
- dd->base_dat.healthy_minutes = dd->iiodat.healthy_minutes;
- dd->base_dat.calories = dd->iiodat.calories;
- m4ped_err("%s: Pedometer bases after panic = %d %d %d %d", __func__,
- dd->base_dat.total_distance, dd->base_dat.total_steps,
- dd->base_dat.healthy_minutes, dd->base_dat.calories);
+ err = m4ped_write_userdata(dd);
+ if (err < 0) {
+ m4ped_err("%s: Failed to write user data (%d).\n",
+ __func__, err);
+ goto m4ped_panic_restore_fail;
+ }
if (!(dd->status & (1 << M4PED_FEATURE_ENABLED_BIT))) {
err = m4sensorhub_reg_write(dd->m4, M4SH_REG_PEDOMETER_ENABLE,
@@ -631,6 +710,19 @@ static void m4ped_panic_restore(struct m4sensorhub_data *m4sensorhub,
goto m4ped_panic_restore_fail;
}
}
+ /* Update base and reset last */
+ dd->base_dat.total_distance = dd->iiodat.total_distance;
+ dd->base_dat.total_steps = dd->iiodat.total_steps;
+ dd->base_dat.healthy_minutes = dd->iiodat.healthy_minutes;
+ dd->base_dat.calories = dd->iiodat.calories;
+ dd->base_dat.calories_normr = dd->iiodat.calories_normr;
+
+ dd->last_dat.total_distance = 0;
+ dd->last_dat.total_steps = 0;
+ dd->last_dat.healthy_minutes = 0;
+ dd->last_dat.calories = 0;
+ dd->last_dat.calories_normr = 0;
+
cancel_delayed_work(&(dd->m4ped_work));
if (dd->samplerate > 0)
queue_delayed_work(system_freezable_wq, &(dd->m4ped_work),
@@ -692,6 +784,12 @@ static int m4ped_probe(struct platform_device *pdev)
dd->fastest_rate = 1000; /* in milli secs */
dd->status = dd->status | (1 << M4PED_FEATURE_ENABLED_BIT);
+ dd->userdata[0] = 0x23; /* Age (35) */
+ dd->userdata[1] = 0x01; /* Gender (Male) */
+ dd->userdata[2] = 0xB2; /* Height (178cm) */
+ dd->userdata[3] = 0x5B; /* Weight (91kg) */
+ dd->userdata[4] = 0x00; /* Weight */
+
err = m4ped_create_iiodev(iio); /* iio and dd are freed on fail */
if (err < 0) {
m4ped_err("%s: Failed to create IIO device.\n", __func__);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5d04f741899..60d5c8e01cb 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2311,6 +2311,8 @@ static const struct mmc_fixup blk_fixups[] =
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("4FEACB", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
MMC_FIXUP("004G90", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile
index 9827e6ce4ec..7b8ef7ee817 100644
--- a/drivers/power/avs/Makefile
+++ b/drivers/power/avs/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
ifneq ($(CONFIG_POWER_TI_HARDWARE_VOLTAGE_CONTROL),)
# OMAP Common
-omap-volt-common = omap_vc.o omap_vp.o
+omap-volt-common = omap_vc.o omap_vp.o omap_core_dvfs.o
# OMAP SoC specific
ifneq ($(CONFIG_ARCH_OMAP3),)
diff --git a/drivers/power/avs/omap_core_dvfs.c b/drivers/power/avs/omap_core_dvfs.c
new file mode 100644
index 00000000000..2f98d534fbb
--- /dev/null
+++ b/drivers/power/avs/omap_core_dvfs.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2014 Motorola Mobility LLC
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#define DRIVER_NAME "omap-core-dvfs"
+
+
+struct omap_core_dvfs_map {
+ unsigned long cpu_freq;
+ unsigned long core_freq;
+};
+
+struct omap_core_dvfs_data {
+ struct device *dev;
+ struct clk *l3_clock;
+ struct clk *dpll_clock;
+ struct regulator *reg;
+ unsigned int volt_tolerance;
+ long curr_freq;
+ struct omap_core_dvfs_map *map;
+};
+
+static struct omap_core_dvfs_data *core_dvfs_data;
+
+static const struct of_device_id omap_core_dvfs_match_tbl[] = {
+ {.compatible = "ti,omap-core-dvfs"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_core_dvfs_match_tbl);
+static int get_match_freq(unsigned long cpu_freq, unsigned long *core_freq)
+{
+ struct omap_core_dvfs_map *map = core_dvfs_data->map;
+ while (map->core_freq && map->cpu_freq) {
+ if (map->cpu_freq == cpu_freq) {
+ *core_freq = map->core_freq;
+ return 0;
+ }
+ map++;
+ }
+ return -ENODATA;
+}
+static int cpufreq_trans(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct cpufreq_freqs *freqs = (struct cpufreq_freqs *)data;
+ struct omap_core_dvfs_data *pdata = core_dvfs_data;
+ int ret = 0;
+ long d, new_freq, dpll_freq, old_freq;
+ struct opp *opp;
+ unsigned long volt = 0, volt_old = 0, tol = 0;
+
+ if (IS_ERR_OR_NULL(freqs))
+ return -ENODATA;
+
+ if (val != CPUFREQ_PRECHANGE || freqs->new == freqs->old)
+ return 0;
+
+ ret = get_match_freq(freqs->new * 1000, &new_freq);
+ if (ret) {
+ pr_err(
+ "Could not find cpu freq %u in core map\n", freqs->new * 1000);
+ goto f_out;
+ }
+ if (pdata->curr_freq == new_freq)
+ return 0;
+
+ /* calculate target frequency to be set in dpll */
+ old_freq = clk_get_rate(pdata->l3_clock);
+ d = clk_get_rate(pdata->dpll_clock) / old_freq;
+ dpll_freq = clk_round_rate(pdata->dpll_clock, new_freq * d);
+ if (dpll_freq < 0)
+ dpll_freq = new_freq * d;
+
+ rcu_read_lock();
+ opp = opp_find_freq_ceil(pdata->dev, &new_freq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ pr_err("failed to find core OPP for %ld\n", new_freq);
+ ret = PTR_ERR(opp);
+ goto f_out;
+ }
+ volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ tol = volt * pdata->volt_tolerance / 100;
+ volt_old = regulator_get_voltage(pdata->reg);
+
+ pr_debug("L3 DVFS %ld MHz, %ld mV --> %ld MHz, %ld mV\n",
+ old_freq / 1000000, volt_old ? volt_old / 1000 : -1,
+ dpll_freq / d / 1000000, volt ? volt / 1000 : -1);
+
+ if (freqs->new > freqs->old) {
+ ret = regulator_set_voltage_tol(pdata->reg, volt, tol);
+ if (ret) {
+ pr_err("failed to scale core voltage up: %d\n", ret);
+ goto f_out;
+ }
+ }
+ ret = clk_set_rate(pdata->dpll_clock, dpll_freq);
+ if (ret) {
+ pr_err("failed to set core clock rate: %d\n", ret);
+ regulator_set_voltage_tol(pdata->reg, volt_old, tol);
+ goto f_out;
+ }
+ if (freqs->new < freqs->old) {
+ ret = regulator_set_voltage_tol(pdata->reg, volt, tol);
+ if (ret) {
+ pr_err("failed to scale voltage down: %d\n", ret);
+ clk_set_rate(pdata->dpll_clock, old_freq * d);
+ goto f_out;
+ }
+ }
+ pdata->curr_freq = new_freq;
+f_out:
+ return ret;
+}
+
+static struct notifier_block cpufreq_trans_block = {
+ .notifier_call = cpufreq_trans
+};
+
+static int of_init_opp_map(struct device *dev, struct omap_core_dvfs_map **map)
+{
+ const struct property *prop;
+ const __be32 *val;
+ struct omap_core_dvfs_map *m;
+ int nr, i;
+
+ prop = of_find_property(dev->of_node, "map", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (!prop->value)
+ return -ENODATA;
+
+ /*
+ * Each entry is a set of tuples consisting of freq-kHz from
+ * OPP CPU list and index of matching OPP in core list.
+ */
+ nr = prop->length / sizeof(u32);
+ if (nr % 2) {
+ dev_err(dev, "Invalid map\n");
+ return -EINVAL;
+ }
+
+ m = devm_kzalloc(dev, prop->length, GFP_KERNEL);
+ if (!m) {
+ dev_err(dev, "Unable to create new map\n");
+ return -ENOMEM;
+ }
+ *map = m;
+ val = prop->value;
+ for (i = 0; i < nr; i += 2, m++) {
+ m->cpu_freq = be32_to_cpup(val++) * 1000;
+ m->core_freq = be32_to_cpup(val++) * 1000;
+ }
+ m->cpu_freq = 0;
+ m->core_freq = 0;
+
+ return 0;
+}
+
+static int omap_core_dvfs_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *nd = dev->of_node;
+ int ret;
+ struct omap_core_dvfs_data *data;
+ const char *pname, *str;
+ struct regulator *reg;
+
+ if (!nd) {
+ dev_err(dev, "no OF information?\n");
+ return -EINVAL;
+ }
+
+ reg = devm_regulator_get(dev, "core_dvfs");
+ if (IS_ERR(reg)) {
+ dev_err(dev, "core_dvfs regulator not ready, retry\n");
+ return -EPROBE_DEFER;
+ }
+
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "Unable to allocate data\n");
+ return -ENOMEM;
+ }
+
+ ret = of_init_opp_table(dev);
+ if (ret) {
+ dev_err(dev, "Failed to init OPP table: %d\n", ret);
+ goto fail;
+ }
+
+ ret = of_init_opp_map(dev, &data->map);
+ if (ret) {
+ dev_err(dev, "Failed to init map: %d\n", ret);
+ goto fail;
+ }
+ pname = "l3_clkname";
+ ret = of_property_read_string(nd, pname, &str);
+ if (ret)
+ goto property_err;
+
+ data->l3_clock = devm_clk_get(dev, str);
+ if (IS_ERR(data->l3_clock)) {
+ ret = PTR_ERR(data->l3_clock);
+ dev_err(dev, "Failed to get %s clock: %d\n", str, ret);
+ goto fail;
+ }
+
+ pname = "dpll_clkname";
+ ret = of_property_read_string(nd, pname, &str);
+ if (ret)
+ goto property_err;
+
+ data->dpll_clock = devm_clk_get(dev, str);
+ if (IS_ERR(data->dpll_clock)) {
+ ret = PTR_ERR(data->dpll_clock);
+ dev_err(dev, "Failed to get %s clock: %d\n", str, ret);
+ goto fail;
+ }
+
+ of_property_read_u32(nd, "voltage-tolerance", &data->volt_tolerance);
+
+ ret = cpufreq_register_notifier(&cpufreq_trans_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (ret) {
+ dev_err(dev, "CPU notifier registration failed with %d\n", ret);
+ cpufreq_unregister_notifier(
+ &cpufreq_trans_block, CPUFREQ_TRANSITION_NOTIFIER);
+ goto fail;
+ }
+ data->reg = reg;
+ data->dev = dev;
+ core_dvfs_data = data;
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+property_err:
+ dev_err(dev, " Missing/Invalid '%s' property\n", pname);
+
+fail:
+ return ret;
+}
+
+static struct platform_driver omap_core_dvfs_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(omap_core_dvfs_match_tbl),
+ },
+ .probe = omap_core_dvfs_probe,
+};
+static int __init omap_core_dvfs_init(void)
+{
+ int ret;
+ ret = platform_driver_register(&omap_core_dvfs_driver);
+ if (ret)
+ pr_err("driver register failed for omap_pmic(%d)\n", ret);
+ return ret;
+}
+device_initcall_sync(omap_core_dvfs_init);
+
+static void __exit omap_core_dvfs_exit(void)
+{
+ platform_driver_unregister(&omap_core_dvfs_driver);
+}
+module_exit(omap_core_dvfs_exit);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Motorola Mobility LLC");
+MODULE_DESCRIPTION("OMAP Global PRM driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 6d0327f120a..c6c70c4afeb 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -64,15 +64,23 @@ CONFIG_TS_BIT_ENBL | CONFIG_SS_BIT_ENBL)
#define MODEL_LOCK1 0X0000
#define MODEL_LOCK2 0X0000
-#define dQ_ACC_DIV 0x4
-#define dP_ACC_100 0x1900
-#define dP_ACC_200 0x3200
+#define MAX17042_INIT_NUM_CYCLES 160
+#define MAX17047_INIT_NUM_CYCLES 96
+
+#define MAX17042_dQ_ACC_DIV 4
+#define MAX17047_dQ_ACC_DIV 16
+
+#define MAX17042_dP_ACC_200 0x3200
+#define MAX17047_dP_ACC_200 0x0C80
#define MAX17042_IC_VERSION 0x0092
#define MAX17047_IC_VERSION 0x00AC /* same for max17050 */
+#define MAX17042_AGE_DIV 256
+
#define INIT_DATA_PROPERTY "maxim,regs-init-data"
#define CONFIG_NODE "maxim,configuration"
+#define VERSION_PROPERTY "version"
#define CONFIG_PROPERTY "config"
#define FULL_SOC_THRESH_PROPERTY "full_soc_thresh"
#define DESIGN_CAP_PROPERTY "design_cap"
@@ -119,6 +127,26 @@ struct max17042_chip {
int malicious_online;
};
+#ifdef CONFIG_OF
+const char *get_dts_batt_id(struct device *dev)
+{
+ int lenp;
+ const char *retval = NULL;
+ struct device_node *n = of_find_node_by_path("/chosen");
+
+ if (n) {
+ retval = of_get_property(n, "batt-id", &lenp);
+ if (!retval || !lenp) {
+ dev_err(dev, "%s: batt-id len %d\n", __func__, lenp);
+ retval = NULL;
+ }
+ of_node_put(n);
+ }
+
+ return retval;
+}
+#endif
+
static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
{
int ret = i2c_smbus_write_word_data(client, reg, value);
@@ -598,8 +626,9 @@ static void max17042_update_capacity_regs(struct max17042_chip *chip)
max17042_write_verify_reg(chip->client, MAX17042_FullCAP,
config->fullcap);
+ /* Set DesignCap to fullcapnom here */
max17042_write_reg(chip->client, MAX17042_DesignCap,
- config->design_cap);
+ config->fullcapnom);
max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom,
config->fullcapnom);
}
@@ -614,10 +643,21 @@ static void max17042_reset_vfsoc0_reg(struct max17042_chip *chip)
max17042_write_reg(chip->client, MAX17042_VFSOC0Enable, VFSOC0_LOCK);
}
+static void max17042_advance_to_coulomb_counter_mode(struct max17042_chip *chip)
+{
+ u16 value = (chip->chip_type == MAX17042 ?
+ MAX17042_INIT_NUM_CYCLES : MAX17047_INIT_NUM_CYCLES);
+ max17042_write_verify_reg(chip->client, MAX17042_Cycles, value);
+}
+
static void max17042_load_new_capacity_params(struct max17042_chip *chip)
{
u16 rep_cap, dq_acc, vfSoc;
u32 rem_cap;
+ u16 dQ_ACC_DIV = (chip->chip_type == MAX17042 ?
+ MAX17042_dQ_ACC_DIV : MAX17047_dQ_ACC_DIV);
+ u16 dP_ACC_200 = (chip->chip_type == MAX17042 ?
+ MAX17042_dP_ACC_200 : MAX17047_dP_ACC_200);
struct max17042_config_data *config = chip->pdata->config_data;
@@ -669,25 +709,14 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
config->soc_alrt_thresh);
max17042_override_por(client, MAX17042_CONFIG, config->config);
max17042_override_por(client, MAX17042_SHDNTIMER, config->shdntimer);
-
- max17042_override_por(client, MAX17042_DesignCap, config->design_cap);
- max17042_override_por(client, MAX17042_ICHGTerm, config->ichgt_term);
-
max17042_override_por(client, MAX17042_AtRate, config->at_rate);
- max17042_override_por(client, MAX17042_LearnCFG, config->learn_cfg);
- max17042_override_por(client, MAX17042_FilterCFG, config->filter_cfg);
- max17042_override_por(client, MAX17042_RelaxCFG, config->relax_cfg);
max17042_override_por(client, MAX17042_MiscCFG, config->misc_cfg);
max17042_override_por(client, MAX17042_MaskSOC, config->masksoc);
- max17042_override_por(client, MAX17042_FullCAP, config->fullcap);
- max17042_override_por(client, MAX17042_FullCAPNom, config->fullcapnom);
if (chip->chip_type == MAX17042)
max17042_override_por(client, MAX17042_SOC_empty,
config->socempty);
max17042_override_por(client, MAX17042_LAvg_empty, config->lavg_empty);
- max17042_override_por(client, MAX17042_dQacc, config->dqacc);
- max17042_override_por(client, MAX17042_dPacc, config->dpacc);
if (chip->chip_type == MAX17042)
max17042_override_por(client, MAX17042_V_empty, config->vempty);
@@ -696,8 +725,6 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
max17042_override_por(client, MAX17042_TempNom, config->temp_nom);
max17042_override_por(client, MAX17042_TempLim, config->temp_lim);
max17042_override_por(client, MAX17042_FCTC, config->fctc);
- max17042_override_por(client, MAX17042_RCOMP0, config->rcomp0);
- max17042_override_por(client, MAX17042_TempCo, config->tcompc0);
if (chip->chip_type == MAX17042) {
max17042_override_por(client, MAX17042_EmptyTempCo,
config->empty_tempco);
@@ -748,6 +775,9 @@ static int max17042_init_chip(struct max17042_chip *chip)
/* reset vfsoc0 reg */
max17042_reset_vfsoc0_reg(chip);
+ /* advance to coulomb-counter mode */
+ max17042_advance_to_coulomb_counter_mode(chip);
+
/* load new capacity params */
max17042_load_new_capacity_params(chip);
@@ -821,8 +851,13 @@ static void max17042_init_worker(struct work_struct *work)
ret = max17042_init_chip(chip);
}
- if (!ret)
+ if (!ret) {
chip->init_complete = 1;
+ if (chip->chip_type == MAX17047) {
+ max17042_write_reg(chip->client, MAX17047_Config_Ver,
+ chip->pdata->config_data->version);
+ }
+ }
mutex_unlock(&chip->lock);
}
@@ -831,11 +866,16 @@ static void max17042_malicious_removed_worker(struct work_struct *work)
{
struct max17042_chip *chip = container_of(work,
struct max17042_chip, work_malicious_removed);
+ int ret;
mutex_lock(&chip->lock);
max17042_perform_soft_POR(chip);
- max17042_init_chip(chip);
+ ret = max17042_init_chip(chip);
+ if (!ret && chip->chip_type == MAX17047)
+ max17042_write_reg(chip->client, MAX17047_Config_Ver,
+ chip->pdata->config_data->version);
+
dev_info(&chip->client->dev, "malicious ps removed, chip re-inited\n");
mutex_unlock(&chip->lock);
@@ -949,6 +989,10 @@ static int max17042_cfg_rqrd_prop(struct device *dev,
struct device_node *np,
struct max17042_config_data *config_data)
{
+ if (of_property_read_u16(np, VERSION_PROPERTY,
+ &config_data->version))
+ return -EINVAL;
+
if (of_property_read_u16(np, CONFIG_PROPERTY,
&config_data->config))
return -EINVAL;
@@ -1008,13 +1052,26 @@ static void max17042_cfg_optnl_prop(struct device_node *np,
static struct max17042_config_data *
max17042_get_config_data(struct device *dev)
{
+ char *config_node = NULL;
+ char config_node_path[64];
struct max17042_config_data *config_data;
struct device_node *np = dev->of_node;
if (!np)
return NULL;
- np = of_get_child_by_name(np, CONFIG_NODE);
+ config_node = (char *)get_dts_batt_id(dev);
+ if (config_node) {
+ snprintf(config_node_path, sizeof(config_node_path),
+ "%s-%s", CONFIG_NODE, config_node);
+ config_node = config_node_path;
+ } else {
+ config_node = CONFIG_NODE;
+ }
+
+ dev_info(dev, "using %s profile\n", config_node);
+
+ np = of_get_child_by_name(np, config_node);
if (!np)
return NULL;
@@ -1175,6 +1232,23 @@ static int max17042_debugfs_write_data(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(data_fops, max17042_debugfs_read_data,
max17042_debugfs_write_data, "0x%02llx\n");
+static int max17042_debugfs_read_capacity(void *data, u64 *val)
+{
+ struct max17042_chip *chip = (struct max17042_chip *)data;
+ *val = chip->debugfs_capacity;
+ return 0;
+}
+
+static int max17042_debugfs_write_capacity(void *data, u64 val)
+{
+ struct max17042_chip *chip = (struct max17042_chip *)data;
+ chip->debugfs_capacity = val;
+ power_supply_changed(&chip->battery);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(capacity_fops, max17042_debugfs_read_capacity,
+ max17042_debugfs_write_capacity, "%llu\n");
+
static int max17042_debugfs_create(struct max17042_chip *chip)
{
chip->debugfs_root = debugfs_create_dir(dev_name(&chip->client->dev),
@@ -1191,8 +1265,8 @@ static int max17042_debugfs_create(struct max17042_chip *chip)
goto err_debugfs;
chip->debugfs_capacity = 0xFF;
- if (!debugfs_create_u8("capacity", S_IRUGO | S_IWUSR,
- chip->debugfs_root, &chip->debugfs_capacity))
+ if (!debugfs_create_file("capacity", S_IRUGO | S_IWUSR,
+ chip->debugfs_root, chip, &capacity_fops))
goto err_debugfs;
return 0;
@@ -1226,7 +1300,6 @@ static void max17042_external_power_changed(struct power_supply *psy)
}
}
-
static ssize_t max17042_show_alert_threshold(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1256,8 +1329,21 @@ static ssize_t max17042_store_alert_threshold(struct device *dev,
static DEVICE_ATTR(alert_threshold, S_IRUGO | S_IWUSR,
max17042_show_alert_threshold, max17042_store_alert_threshold);
+
+static ssize_t max17042_show_battery_age(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct max17042_chip *chip = dev_get_drvdata(dev);
+ int ret = max17042_read_reg(chip->client, MAX17042_Age);
+
+ return ret < 0 ? ret : sprintf(buf, "%u\n", ret / MAX17042_AGE_DIV);
+}
+static DEVICE_ATTR(battery_age, S_IRUGO, max17042_show_battery_age, NULL);
+
static struct attribute *max17042_attrs[] = {
&dev_attr_alert_threshold.attr,
+ &dev_attr_battery_age.attr,
NULL,
};
@@ -1265,6 +1351,20 @@ static struct attribute_group max17042_attr_group = {
.attrs = max17042_attrs,
};
+static bool max17042_new_config_data(struct max17042_chip *chip)
+{
+ int ret;
+
+ if (chip->chip_type == MAX17042)
+ return false;
+
+ ret = max17042_read_reg(chip->client, MAX17047_Config_Ver);
+ if (ret < 0)
+ return false;
+
+ return (chip->pdata->config_data->version != ret);
+}
+
static int max17042_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1384,7 +1484,7 @@ static int max17042_probe(struct i2c_client *client,
}
reg = max17042_read_reg(chip->client, MAX17042_STATUS);
- if (reg & STATUS_POR_BIT) {
+ if (reg & STATUS_POR_BIT || max17042_new_config_data(chip)) {
INIT_WORK(&chip->work, max17042_init_worker);
schedule_work(&chip->work);
} else {
diff --git a/drivers/regulator/omap-pmic-regulator.c b/drivers/regulator/omap-pmic-regulator.c
index a19f9ebb7de..2eab7c158e2 100644
--- a/drivers/regulator/omap-pmic-regulator.c
+++ b/drivers/regulator/omap-pmic-regulator.c
@@ -661,7 +661,22 @@ static struct platform_driver omap_pmic_driver = {
},
.probe = omap_pmic_probe,
};
-module_platform_driver(omap_pmic_driver);
+
+static int __init omap_pmic_init(void)
+{
+ int ret;
+ ret = platform_driver_register(&omap_pmic_driver);
+ if (ret)
+ pr_err("driver register failed for omap_pmic (%d)\n", ret);
+ return ret;
+}
+device_initcall_sync(omap_pmic_init);
+
+static void __exit omap_pmic_exit(void)
+{
+ platform_driver_unregister(&omap_pmic_driver);
+}
+module_exit(omap_pmic_exit);
MODULE_DESCRIPTION("OMAP Generic PMIC Regulator");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-sensorhub.c b/drivers/rtc/rtc-sensorhub.c
index f4e713d741f..16f95758f93 100644
--- a/drivers/rtc/rtc-sensorhub.c
+++ b/drivers/rtc/rtc-sensorhub.c
@@ -223,6 +223,9 @@ static int rtc_sensorhub_rtc_set_time(struct device *p_dev,
"set time, but failed to set M4 clock!\n");
return -EIO;
}
+ dev_dbg(p_dev, "Set RTC time to %d-%02d-%02d %02d:%02d:%02d UTC (%ld)\n",
+ p_tm->tm_year + 1900, p_tm->tm_mon + 1, p_tm->tm_mday,
+ p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec, sec);
return 0;
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 7d041f28cf2..3009a8909cc 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -172,6 +172,7 @@ struct uart_omap_port {
struct pinctrl_state *pin_default;
struct pinctrl_state *pin_idle;
bool is_suspending;
+ spinlock_t delayed_rts_lock; /* protect need_delayed_rts*/
bool need_delayed_rts;
bool in_transmit;
int ext_rt_cnt;
@@ -1372,12 +1373,16 @@ static int serial_omap_prepare(struct device *dev)
static void serial_omap_complete(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->delayed_rts_lock, flags);
if (up->need_delayed_rts && up->pin_default && up->pin_idle) {
pinctrl_select_state(up->pins, up->pin_default);
up->need_delayed_rts = 0;
}
up->is_suspending = false;
+ spin_unlock_irqrestore(&up->delayed_rts_lock, flags);
}
static int serial_omap_suspend(struct device *dev)
@@ -1747,6 +1752,7 @@ static void serial_omap_restore_context(struct uart_omap_port *up)
static int serial_omap_runtime_suspend(struct device *dev)
{
struct uart_omap_port *up = dev_get_drvdata(dev);
+ unsigned long flags;
/*
* When using 'no_console_suspend', the console UART must not be
@@ -1762,8 +1768,10 @@ static int serial_omap_runtime_suspend(struct device *dev)
return -EINVAL;
if (up->pin_idle) {
+ spin_lock_irqsave(&up->delayed_rts_lock, flags);
pinctrl_select_state(up->pins, up->pin_idle);
up->need_delayed_rts = 0;
+ spin_unlock_irqrestore(&up->delayed_rts_lock, flags);
}
up->context_loss_cnt = serial_omap_get_context_loss_count(up);
diff --git a/drivers/video/omap2/displays/panel-minnow-common.h b/drivers/video/omap2/displays/panel-minnow-common.h
index 1001cc67f46..13ce3050a9e 100644
--- a/drivers/video/omap2/displays/panel-minnow-common.h
+++ b/drivers/video/omap2/displays/panel-minnow-common.h
@@ -18,7 +18,7 @@
#ifndef _MINNOW_PANEL_COMMON_HEADER_
-#define INIT_DATA_VERSION (0x072314) /*MM/DD/YY*/
+#define INIT_DATA_VERSION (0x081214) /*MM/DD/YY*/
/* This header file is used to sync Bootloader and Kernel Display Initialize
* Structure/Data, please make sure sync it for both Bootloader/Kernel when
* it changes some settings for Solomon/Orise. Bootloader should pass
@@ -215,8 +215,8 @@ static u8 panel_init_ssd2848_320x320[] = {
2, OTM3201_CMD, 0xE9, 0x46,
/* Display Inversion Control (RB1h) */
2, OTM3201_CMD, 0xB1, 0x12,
-/* ??? undefined */
-2, OTM3201_CMD, 0xE2, 0xF0,
+/* MIPI RX Delay Setting (RE2h) */
+2, OTM3201_CMD, 0xE2, 0xF5,
/* Display Waveform Cycle setting (RBAh) */
5, OTM3201_CMD, 0xBA, 0x06, 0x15, 0x2B, 0x01,
/* RGB Interface Blanking Porch setting (RB3h)
diff --git a/drivers/video/omap2/displays/panel-minnow.c b/drivers/video/omap2/displays/panel-minnow.c
index 8d127ae401f..d1014b0af1d 100644
--- a/drivers/video/omap2/displays/panel-minnow.c
+++ b/drivers/video/omap2/displays/panel-minnow.c
@@ -302,6 +302,8 @@ struct minnow_panel_data {
int id_panel;
int x_offset;
int y_offset;
+ int xres_um;
+ int yres_um;
int reset_ms;
int release_ms;
@@ -439,6 +441,27 @@ static void minnow_panel_sync_resume_mlocked(struct minnow_panel_data *mpd)
#endif
#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
+static char *action_to_str(unsigned long action)
+{
+ switch (action) {
+ case DISPLAY_WAKE_EVENT_POWERKEY:
+ return "power_key";
+ case DISPLAY_WAKE_EVENT_TOUCH:
+ return "touch";
+ case DISPLAY_WAKE_EVENT_GESTURE:
+ return "gesture_wrist";
+ case DISPLAY_WAKE_EVENT_GESTURE_VIEWON:
+ return "gesture_view_on";
+ case DISPLAY_WAKE_EVENT_GESTURE_VIEWOFF:
+ return "gesture_view_off";
+ case DISPLAY_WAKE_EVENT_DOCKON:
+ return "dock_on";
+ case DISPLAY_WAKE_EVENT_DOCKOFF:
+ return "dock_off";
+ }
+ return "unsupported";
+}
+
static int omapdss_displayenable_notify(struct notifier_block *self,
unsigned long action, void *dev)
{
@@ -448,7 +471,8 @@ static int omapdss_displayenable_notify(struct notifier_block *self,
if (GET_WAKEUP_EVENT_TYPE(action) != WAKEUP_DISPLAY)
return NOTIFY_OK;
- dev_info(&mpd->dssdev->dev, "%s, action is %lu", __func__, action);
+ dev_info(&mpd->dssdev->dev, "%s, action is %lu-%s",
+ __func__, action, action_to_str(action));
switch (action) {
case DISPLAY_WAKE_EVENT_POWERKEY:
@@ -1420,6 +1444,14 @@ static void minnow_panel_get_resolution(struct omap_dss_device *dssdev,
*yres = dssdev->panel.timings.y_res;
}
+static void minnow_panel_get_dimensions(struct omap_dss_device *dssdev,
+ u32 *xres, u32 *yres)
+{
+ struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ *xres = mpd->xres_um;
+ *yres = mpd->yres_um;
+}
+
static ssize_t minnow_panel_errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1874,6 +1906,49 @@ static ssize_t minnow_panel_store_interactivemode(struct device *dev,
return r ? r : count;
}
+static ssize_t minnow_panel_show_smartambient(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ unsigned t;
+
+ t = mpd->smart_ambient;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t minnow_panel_store_smartambient(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct omap_dss_device *dssdev = to_dss_device(dev);
+ struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
+ unsigned long t;
+ int r;
+ bool enable;
+
+ r = kstrtoul(buf, 10, &t);
+ if (!r) {
+ mutex_lock(&mpd->lock);
+ enable = !!t;
+ if (mpd->state != DISPLAY_ENABLE) {
+ dev_err(&dssdev->dev, "%s failed as display is not enabled\n",
+ __func__);
+ r = -EBUSY;
+ } else if (mpd->smart_ambient != enable) {
+ mpd->smart_ambient = enable;
+ }
+ mutex_unlock(&mpd->lock);
+ if (r)
+ dev_err(&dssdev->dev, "setting smartambient_status to %ld failed %d\n",
+ t, r);
+ else
+ dev_dbg(&dssdev->dev, "setting smartambient_status to %ld succeeded\n",
+ t);
+ }
+
+ return r ? r : count;
+}
static ssize_t minnow_panel_show_ambient_timeout(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2050,6 +2125,9 @@ static DEVICE_ATTR(init_data, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(interactivemode, S_IRUGO | S_IWUSR,
minnow_panel_show_interactivemode,
minnow_panel_store_interactivemode);
+static DEVICE_ATTR(smartambient, S_IRUSR | S_IWUSR,
+ minnow_panel_show_smartambient,
+ minnow_panel_store_smartambient);
static DEVICE_ATTR(ambient_timeout, S_IRUGO | S_IWUSR,
minnow_panel_show_ambient_timeout,
minnow_panel_store_ambient_timeout);
@@ -2076,6 +2154,7 @@ static struct attribute *minnow_panel_attrs[] = {
#endif
#ifdef CONFIG_HAS_AMBIENTMODE
&dev_attr_interactivemode.attr,
+ &dev_attr_smartambient.attr,
&dev_attr_ambient_timeout.attr,
#endif
#ifdef PANEL_PERF_TIME
@@ -2409,6 +2488,15 @@ static int minnow_panel_dt_init(struct minnow_panel_data *mpd)
mpd->dsi_config.lp_clk_max);
}
+ mpd->xres_um = 0;
+ mpd->yres_um = 0;
+ if (!of_property_read_u32_array(dt_node, "panel_size_um", range, 2)) {
+ mpd->xres_um = range[0];
+ mpd->yres_um = range[1];
+ DTINFO("physical panel width = %d um, height = %d um\n",
+ mpd->xres_um, mpd->yres_um);
+ }
+
return 0;
}
@@ -2453,6 +2541,7 @@ static int minnow_panel_probe(struct omap_dss_device *dssdev)
mpd->dssdev = dssdev;
mpd->first_enable = true;
mpd->m4_state = DISPLAY_ENABLE;
+ mpd->interactive = true;
r = minnow_panel_dt_init(mpd);
if (r)
@@ -3030,8 +3119,9 @@ static int minnow_panel_enable_mlocked(struct minnow_panel_data *mpd)
bool update;
int r = 0;
- dev_info(&dssdev->dev, "%s: current state = %d\n",
- __func__, dssdev->state);
+ dev_info(&dssdev->dev, "%s: current display is %s\n", __func__,
+ dssdev->state == OMAP_DSS_DISPLAY_DISABLED
+ ? "disabled" : "enabled");
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) {
wake_lock(&mpd->wake_lock);
@@ -3067,8 +3157,9 @@ static void minnow_panel_disable_mlocked(struct minnow_panel_data *mpd)
{
struct omap_dss_device *dssdev = mpd->dssdev;
- dev_info(&dssdev->dev, "%s: current state = %d\n",
- __func__, dssdev->state);
+ dev_info(&dssdev->dev, "%s: current display is %s\n", __func__,
+ dssdev->state == OMAP_DSS_DISPLAY_DISABLED
+ ? "disabled" : "enabled");
wake_lock(&mpd->wake_lock);
mpd->early_inited = false;
@@ -3091,7 +3182,6 @@ static void minnow_panel_disable_mlocked(struct minnow_panel_data *mpd)
static void minnow_panel_sync_display_status_mlocked(
struct minnow_panel_data *mpd)
{
- struct m4sensorhub_data *m4sensorhub;
enum display_state m4_state = mpd->state;
/* special case for dock mode, set to DISPLAY_ENABLE
* to block all wakeup gestures
@@ -3104,21 +3194,19 @@ static void minnow_panel_sync_display_status_mlocked(
/* be safety to sync resume states first */
minnow_panel_sync_resume_mlocked(mpd);
- m4sensorhub = m4sensorhub_client_get_drvdata();
- if (m4sensorhub->mode != NORMALMODE) {
+ if (m4sensorhub_get_current_mode() != NORMALMODE) {
dev_err(&mpd->dssdev->dev,
"M4 is not ready, unable to set screen status(%d)\n",
m4_state);
return;
}
- if (m4sensorhub_reg_write_1byte(m4sensorhub,
- M4SH_REG_USERSETTINGS_SCREENSTATUS,
- m4_state, 0xFF) != 1) {
+
+ if (m4sensorhub_extern_set_display_status(m4_state) < 0) {
dev_err(&mpd->dssdev->dev,
- "Unable to set screen status(%d) to M4\n",
- m4_state);
+ "Unable to set screen status(%d) to M4\n", m4_state);
return;
}
+
dev_dbg(&mpd->dssdev->dev,
"Set screen status(%d) to M4 success!\n", m4_state);
mpd->m4_state = m4_state;
@@ -3145,13 +3233,32 @@ static void led_set_dim_brightness(struct device *dev)
}
#endif /* CONFIG_HAS_AMBIENTMODE */
+static char *state_to_str(enum display_state state)
+{
+ switch (state) {
+ case DISPLAY_DISABLE:
+ return "normal_off";
+ case DISPLAY_ENABLE:
+ return "normal_on";
+#ifdef CONFIG_HAS_AMBIENTMODE
+ case DISPLAY_AMBIENT_OFF:
+ return "ambient_off";
+ case DISPLAY_AMBIENT_ON:
+ return "ambient_on";
+#endif
+ }
+ return "unknown???";
+}
+
static int minnow_panel_change_state_mlocked(struct minnow_panel_data *mpd,
int state)
{
int r = 0;
dev_info(&mpd->dssdev->dev,
- "change state %d ==> %d\n", mpd->state, state);
+ "change state %d(%s) ==> %d(%s)\n",
+ mpd->state, state_to_str(mpd->state),
+ state, state_to_str(state));
/* already in state, return success */
if (state == mpd->state) {
@@ -3364,7 +3471,7 @@ static void minnow_panel_te_timeout_work_callback(struct work_struct *work)
static int minnow_panel_enable(struct omap_dss_device *dssdev)
{
struct minnow_panel_data *mpd = dev_get_drvdata(&dssdev->dev);
- int r;
+ int r, state;
mutex_lock(&mpd->lock);
#ifdef CONFIG_WAKEUP_SOURCE_NOTIFY
@@ -3374,7 +3481,12 @@ static int minnow_panel_enable(struct omap_dss_device *dssdev)
cancel_delayed_work(&mpd->early_init_timeout_work);
}
#endif
- r = minnow_panel_change_state_mlocked(mpd, DISPLAY_ENABLE);
+ state = DISPLAY_ENABLE;
+#ifdef CONFIG_HAS_AMBIENTMODE
+ if (!mpd->interactive)
+ state = DISPLAY_AMBIENT_ON;
+#endif
+ r = minnow_panel_change_state_mlocked(mpd, state);
mutex_unlock(&mpd->lock);
return r;
}
@@ -3726,6 +3838,7 @@ static struct omap_dss_driver minnow_panel_driver = {
.sync = minnow_panel_sync,
.get_resolution = minnow_panel_get_resolution,
+ .get_dimensions = minnow_panel_get_dimensions,
.get_recommended_bpp = omapdss_default_get_recommended_bpp,
.enable_te = minnow_panel_enable_te,