summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjeongsup.jeong <jeongsup.jeong@samsung.com>2019-07-22 18:39:34 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2020-05-11 00:41:14 +0000
commit58c9cdc9071f28c64e5d2f5122dd0581a2fe052a (patch)
tree0cb892bd24b257a6d5475b7e2926bb9764d29f5b
parentdbf66c0cc1fa40f5fd9a9ad98c8ba8aa8cd021d0 (diff)
downloadlinux-4.9-exynos9110-58c9cdc9071f28c64e5d2f5122dd0581a2fe052a.tar.gz
linux-4.9-exynos9110-58c9cdc9071f28c64e5d2f5122dd0581a2fe052a.tar.bz2
linux-4.9-exynos9110-58c9cdc9071f28c64e5d2f5122dd0581a2fe052a.zip
Motor: add handling freq, overdrive param on ff effect
In order to handle the motor behavior in details, add new 'frequency' and 'overdrive' parameter for ff (force feedback) effect. Use the existing 'struct ff_runbm_effect' without any added variable to pass the user data to input device driver of kernel. Change-Id: I3f1e7ed8b280bdbfdf50bab7299d0f2b67ad3914 Signed-off-by: jeongsup.jeong <jeongsup.jeong@samsung.com> [cw00.choi: Add commit-msg as public style and fix the merge conflict] Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--drivers/motor/ztm620_motor.c157
-rw-r--r--include/linux/ztm620_motor.h12
2 files changed, 106 insertions, 63 deletions
diff --git a/drivers/motor/ztm620_motor.c b/drivers/motor/ztm620_motor.c
index 0003ec0e98da..f3f2269f4a50 100644
--- a/drivers/motor/ztm620_motor.c
+++ b/drivers/motor/ztm620_motor.c
@@ -105,31 +105,44 @@ static int ztm620_motor_set_bits(struct ztm620_motor_data *pMotorData,
static int ztm620_motor_run(void) {
int ret = -EINVAL;
unsigned char val, strength;
- int freq;
+ int freq_reg, freq_hz;
struct ztm620_motor_data *pMotorData = g_Ztm620MotorData;
struct ztm620_motor_platform_data *pMotorPdata;
- if (pMotorData == NULL) {
+ if (!pMotorData) {
pr_err("[VIB] %s ztm620_motor_data NULL error\n", __func__);
goto out;
}
else
pMotorPdata = &pMotorData->msPlatData;
- if (pMotorData->level == 0) {
+ if (!(pMotorData->level)) {
pr_err("[VIB] %s: level 0\n", __func__);
goto out;
}
ret = ztm620_motor_reg_write(pMotorData, MOTOR_REG_SOFT_EN, SOFT_ENABLE);
if (ret < 0) {
- pr_err("[VIB] %s SOFT_EN write fail %d\n",
- __func__, ret);
+ pr_err("[VIB] %s SOFT_EN write fail (%d)\n", __func__, ret);
goto out;
}
+
if (pMotorPdata->soft_en_delay)
msleep(pMotorPdata->soft_en_delay);
+ if (pMotorData->overdrive && pMotorPdata->overdrive_num) {
+ val = (pMotorData->overdrive & MOTOR_REG_OVER_DRV_EN_MASK)
+ << OVER_DRV_SHIFT_EN;
+ val |= (pMotorPdata->overdrive_num & MOTOR_REG_OVER_DRV_CNT_MASK)
+ << OVER_DRV_SHIFT_CNT;
+ ret = ztm620_motor_reg_write(pMotorData, MOTOR_REG_OVER_DRV, val);
+ if (ret < 0) {
+ pr_err("[VIB] %s OVER_DRV 0x%02x write fail (%d)\n",
+ __func__, MOTOR_REG_OVER_DRV, ret);
+ goto out;
+ }
+ }
+
if (pMotorData->level >= MAX_LEVEL)
strength = pMotorPdata->strength_strong;
else
@@ -137,17 +150,17 @@ static int ztm620_motor_run(void) {
ret = ztm620_motor_reg_write(pMotorData, MOTOR_REG_STRENGTH, strength);
if (ret < 0) {
- pr_err("[VIB] %s STRENGTH write %d fail %d\n",
- __func__, strength, ret);
+ pr_err("[VIB] %s STRENGTH 0x%02x write %d fail (%d)\n",
+ __func__, MOTOR_REG_STRENGTH, strength, ret);
goto out;
}
- val = (pMotorPdata->meLoop << MODE_01_SHIFT_DRV_MODE );
- ret = ztm620_motor_set_bits(pMotorData,
- MOTOR_REG_MODE_01, (1 << MODE_01_SHIFT_DRV_MODE), val);
+ ret = ztm620_motor_set_bits(pMotorData, MOTOR_REG_MODE_01,
+ 1 << MODE_01_SHIFT_DRV_MODE,
+ pMotorPdata->meLoop << MODE_01_SHIFT_DRV_MODE);
if (ret < 0) {
pr_err("[VIB] %s MODE_01 0x%02x write fail (%d)\n",
- __func__, MOTOR_REG_MODE_01, ret);
+ __func__, MOTOR_REG_MODE_01, ret);
goto out;
}
@@ -156,49 +169,60 @@ static int ztm620_motor_run(void) {
Clock Frequency / (16 Clocks * Driving Frequency)
DRV_FREQ_H[7:0] = DRV_FREQ[15:8]
DRV_FREQ_L[7:0] = DRV_FREQ[7:0] */
- if (pMotorData->level >= MAX_LEVEL)
- freq = MOTOR_CLK / (16 * pMotorPdata->freq_strong);
- else
- freq = MOTOR_CLK / (16 * pMotorPdata->freq_weak);
+ if (pMotorData->level >= MAX_LEVEL) {
+ if (pMotorPdata->freq_strong)
+ freq_hz = pMotorPdata->freq_strong;
+ else if (pMotorData->frequency)
+ freq_hz = pMotorData->frequency;
+ else
+ freq_hz = DEFAULT_MOTOR_FREQ;
+ } else {
+ if (pMotorPdata->freq_weak)
+ freq_hz = pMotorPdata->freq_weak;
+ else if (pMotorData->frequency)
+ freq_hz = pMotorData->frequency;
+ else
+ freq_hz = DEFAULT_MOTOR_FREQ;
+ }
+ freq_reg = (MOTOR_CLK * 10) / (freq_hz * 16);
ret = ztm620_motor_reg_write(pMotorData,
- MOTOR_REG_DRV_FREQ_H, freq / 256);
+ MOTOR_REG_DRV_FREQ_H, freq_reg / 256);
if (ret < 0) {
pr_err("[VIB] %s DRV_FREQ_H 0x%02x write fail (%d)\n",
- __func__, MOTOR_REG_DRV_FREQ_H, ret);
+ __func__, MOTOR_REG_DRV_FREQ_H, ret);
goto out;
}
ret = ztm620_motor_reg_write(pMotorData,
- MOTOR_REG_DRV_FREQ_L, freq % 256);
+ MOTOR_REG_DRV_FREQ_L, freq_reg % 256);
if (ret < 0) {
pr_err("[VIB] %s DRV_FREQ_L 0x%02x write fail (%d)\n",
- __func__, MOTOR_REG_DRV_FREQ_L, ret);
+ __func__, MOTOR_REG_DRV_FREQ_L, ret);
goto out;
}
ret = ztm620_motor_reg_write(pMotorData,
- MOTOR_REG_RESO_FREQ_H, freq / 256);
+ MOTOR_REG_RESO_FREQ_H, freq_reg / 256);
if (ret < 0) {
pr_err("[VIB] %s RESO_FREQ_H 0x%02x write fail (%d)\n",
- __func__, MOTOR_REG_RESO_FREQ_H, ret);
+ __func__, MOTOR_REG_RESO_FREQ_H, ret);
goto out;
}
ret = ztm620_motor_reg_write(pMotorData,
- MOTOR_REG_RESO_FREQ_L, freq % 256);
+ MOTOR_REG_RESO_FREQ_L, freq_reg % 256);
if (ret < 0) {
pr_err("[VIB] %s RESO_FREQ_L 0x%02x write fail (%d)\n",
- __func__, MOTOR_REG_RESO_FREQ_L, ret);
+ __func__, MOTOR_REG_RESO_FREQ_L, ret);
goto out;
}
- val = pMotorPdata->adc_sampling_time;
ret = ztm620_motor_reg_write(pMotorData,
- MOTOR_REG_ADC_SAMPLING_TIME, val);
+ MOTOR_REG_ADC_SAMPLING_TIME, pMotorPdata->adc_sampling_time);
if (ret < 0) {
- pr_err("[VIB] %s ADC_SAMPLING_TIME write fail %d\n",
- __func__, ret);
+ pr_err("[VIB] %s ADC_SAMPLING_TIME 0x%02x write fail (%d)\n",
+ __func__, MOTOR_REG_ADC_SAMPLING_TIME, ret);
goto out;
}
@@ -208,16 +232,18 @@ static int ztm620_motor_run(void) {
}
ret = ztm620_motor_reg_write(pMotorData,
- MOTOR_REG_MODE_00, pMotorPdata->motor_start_data);
+ MOTOR_REG_MODE_00, pMotorPdata->motor_start_data);
if (ret < 0) {
- pr_err("[VIB] %s MODE_00 write fail %d\n",
- __func__, ret);
+ pr_err("[VIB] %s MODE_00 write fail (%d)\n", __func__, ret);
goto out;
}
pMotorData->running = true;
}
- pr_info("[VIB] %s Run: level:0x%x freq:0x%x str:0x%x\n",
- __func__, pMotorData->level, freq, strength);
+
+ pr_info("[VIB] Start: str 0x%x(0x%x) freq 0x%x(%d.%d) ovd %d\n",
+ strength, pMotorData->level,
+ freq_reg, freq_hz / 10, freq_hz % 10,
+ pMotorData->overdrive?pMotorPdata->overdrive_num:-1);
out:
return ret;
@@ -269,7 +295,7 @@ static void vibrator_work_routine(struct work_struct *work)
}
pMotorData->running = false;
pMotorData->last_motor_off = CURRENT_TIME;
- pr_info("[VIB] %s Stop\n", __func__);
+ pr_info("[VIB] Stop\n");
}
out:
@@ -323,6 +349,10 @@ static int ztm620_motor_haptic_play(struct input_dev *input, void *data,
{
struct ztm620_motor_data *pMotorData = input_get_drvdata(input);
__u16 level = effect->u.rumble.strong_magnitude;
+ /* [14:0] */
+ pMotorData->frequency = effect->u.rumble.weak_magnitude & 0x7fff;
+ /* [15:15] */
+ pMotorData->overdrive = !!(effect->u.rumble.weak_magnitude & 0x8000 >> 15);
if (level) {
pMotorData->level = level;
@@ -580,13 +610,11 @@ static int of_ztm620_motor_dt(struct i2c_client* client, struct ztm620_motor_pla
pdata->motor_type = ACTUATOR_LRA;
pdata->motor_start_data = MODE_00_I2C_LRA;
pdata->motor_stop_data = MODE_00_STOP_LRA;
- }
- else if (!strcmp(motor_type, "ERM")) {
+ } else if (!strcmp(motor_type, "ERM")) {
pdata->motor_type = ACTUATOR_ERM;
pdata->motor_start_data = MODE_00_I2C_ERM;
pdata->motor_stop_data = MODE_00_STOP_ERM;
- }
- else {
+ } else {
dev_err(&client->dev, "[VIB] %s Wrong motor type: %s\n",
__func__, motor_type);
return -ENODEV;
@@ -621,8 +649,7 @@ static int of_ztm620_motor_dt(struct i2c_client* client, struct ztm620_motor_pla
pdata->break_delay = DEFAULT_BRAKE_DELAY;
dev_warn(&client->dev, "[VIB] %s: brake-delay-ms read fail(%d) :%d\n",
__func__, err, pdata->break_delay);
- }
- else
+ } else
pr_info("[VIB] brake-delay-ms = %d\n", pdata->break_delay);
pdata->count_init_regs = of_property_count_u32_elems(client->dev.of_node,
@@ -657,62 +684,70 @@ static int of_ztm620_motor_dt(struct i2c_client* client, struct ztm620_motor_pla
"ztm620_motor,adc-sampling-time", &pdata->adc_sampling_time);
if (err < 0) {
pdata->adc_sampling_time = DEFAULT_ADC_SAMPLING_TIME;
- dev_warn(&client->dev, "[VIB] %s: adc-sampling-time read fail(%d) :%d\n",
+ pr_warn("[VIB] %s: adc-sampling-time read fail(%d) :%d\n",
__func__, err, pdata->adc_sampling_time);
- }
- else
+ } else
pr_info("[VIB] adc-sampling-time = %d\n", pdata->adc_sampling_time);
err = of_property_read_u32(client->dev.of_node,
"ztm620_motor,soft-en-delay-ms", &pdata->soft_en_delay);
if (err < 0) {
pdata->soft_en_delay = DEFAULT_SOFT_EN_DELAY;
- dev_warn(&client->dev, "[VIB] %s: soft-en-delay-ms read fail(%d) :%d\n",
+ pr_warn("[VIB] %s: soft-en-delay-ms read fail(%d) :%d\n",
__func__, err, pdata->soft_en_delay);
- }
- else
+ } else
pr_info("[VIB] soft-en-delay-ms = %d\n", pdata->soft_en_delay);
err = of_property_read_u32(client->dev.of_node,
"ztm620_motor,freq-strong", &pdata->freq_strong);
- if (err < 0) {
- pdata->freq_strong = DEFAULT_MOTOR_FREQ;
- dev_warn(&client->dev, "[VIB] %s: freq-strong read fail(%d) :%d\n",
+ if (err < 0)
+ pr_warn("[VIB] %s: freq-strong read fail(%d) :%d\n",
__func__, err, pdata->freq_strong);
+ else {
+ /* TBD: need to handle float value from dt */
+ pdata->freq_strong *= 10;
+ pr_info("[VIB] freq-strong = %d.%d\n",
+ pdata->freq_strong / 10, pdata->freq_strong % 10);
}
- else
- pr_info("[VIB] freq-strong = %d\n", pdata->freq_strong);
err = of_property_read_u32(client->dev.of_node,
"ztm620_motor,freq-weak", &pdata->freq_weak);
- if (err < 0) {
- pdata->freq_weak = DEFAULT_MOTOR_FREQ;
- dev_warn(&client->dev, "[VIB] %s: freq-weak read fail(%d) :%d\n",
+ if (err < 0)
+ pr_warn("[VIB] %s: freq-weak read fail(%d) :%d\n",
__func__, err, pdata->freq_weak);
+ else {
+ /* TBD: need to handle float value from dt */
+ pdata->freq_weak *= 10;
+ pr_info("[VIB] freq-weak = %d.%d\n",
+ pdata->freq_weak / 10, pdata->freq_weak % 10);
}
- else
- pr_info("[VIB] freq-weak = %d\n", pdata->freq_weak);
err = of_property_read_u32(client->dev.of_node,
"ztm620_motor,strength-strong", &pdata->strength_strong);
if (err < 0) {
pdata->strength_strong = DEFAULT_MOTOR_STRENGTH;
- dev_warn(&client->dev, "[VIB] %s: strength-strong read fail(%d) :%d\n",
+ pr_warn("[VIB] %s: strength-strong read fail(%d) :%d\n",
__func__, err, pdata->strength_strong);
- }
- else
+ } else
pr_info("[VIB] strength-strong = %d\n", pdata->strength_strong);
err = of_property_read_u32(client->dev.of_node,
"ztm620_motor,strength-weak", &pdata->strength_weak);
if (err < 0) {
pdata->strength_weak = DEFAULT_MOTOR_STRENGTH;
- dev_warn(&client->dev, "[VIB] %s: strength-weak read fail(%d) :%d\n",
+ pr_warn("[VIB] %s: strength-weak read fail(%d) :%d\n",
__func__, err, pdata->strength_weak);
- }
- else
+ } else
pr_info("[VIB] strength-weak = %d\n", pdata->strength_weak);
+ err = of_property_read_u32(client->dev.of_node,
+ "ztm620_motor,overdrive-num", &pdata->overdrive_num);
+ if (err < 0) {
+ pr_warn("[VIB] %s: overdrive-num read fail(%d) :%d\n",
+ __func__, err, pdata->overdrive_num);
+ } else
+ pr_info("[VIB] overdrive-num = %d\n", pdata->overdrive_num);
+
dev_info(&client->dev, "[VIB] %s: dt parsing done\n", __func__);
return ret;
diff --git a/include/linux/ztm620_motor.h b/include/linux/ztm620_motor.h
index 0111b06e0ed5..a8e0c458bf84 100644
--- a/include/linux/ztm620_motor.h
+++ b/include/linux/ztm620_motor.h
@@ -83,6 +83,11 @@
#define MODE_13_SHIFT_PWR_CAL_EN 0x03
#define MODE_13_SHIFT_ERM_NLRA 0x00
+#define MOTOR_REG_OVER_DRV_EN_MASK 0x01
+#define MOTOR_REG_OVER_DRV_CNT_MASK 0x7F
+#define OVER_DRV_SHIFT_EN 7
+#define OVER_DRV_SHIFT_CNT 0
+
#define MAX_LEVEL 0xffff
#define DEFAULT_MOTOR_FREQ 205
#define DEFAULT_MOTOR_STRENGTH 0x56
@@ -123,10 +128,11 @@ struct ztm620_motor_platform_data {
const char *regulator_name;
int adc_sampling_time;
int soft_en_delay;
- int freq_strong;
- int freq_weak;
+ int freq_strong; /* in 0.1 hz*/
+ int freq_weak; /* in 0.1 hz*/
int strength_strong;
int strength_weak;
+ int overdrive_num;
int motor_start_data;
int motor_stop_data;
};
@@ -146,6 +152,8 @@ struct ztm620_motor_data {
/* using FF_input_device */
__u16 level;
+ __u16 frequency; /* in 0.1 hz*/
+ __u16 overdrive;
bool running;
struct regulator *regulator;
int gpio_en;