1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Spreadtrum Communications Inc.
6 #include <linux/module.h>
7 #include <linux/of_address.h>
8 #include <linux/platform_device.h>
9 #include <linux/regmap.h>
10 #include <linux/input.h>
11 #include <linux/workqueue.h>
13 #define CUR_DRV_CAL_SEL GENMASK(13, 12)
14 #define SLP_LDOVIBR_PD_EN BIT(9)
15 #define LDO_VIBR_PD BIT(8)
18 struct input_dev
*input_dev
;
19 struct work_struct play_work
;
20 struct regmap
*regmap
;
26 static void sc27xx_vibra_set(struct vibra_info
*info
, bool on
)
29 regmap_update_bits(info
->regmap
, info
->base
, LDO_VIBR_PD
, 0);
30 regmap_update_bits(info
->regmap
, info
->base
,
31 SLP_LDOVIBR_PD_EN
, 0);
34 regmap_update_bits(info
->regmap
, info
->base
, LDO_VIBR_PD
,
36 regmap_update_bits(info
->regmap
, info
->base
,
37 SLP_LDOVIBR_PD_EN
, SLP_LDOVIBR_PD_EN
);
38 info
->enabled
= false;
42 static int sc27xx_vibra_hw_init(struct vibra_info
*info
)
44 return regmap_update_bits(info
->regmap
, info
->base
, CUR_DRV_CAL_SEL
, 0);
47 static void sc27xx_vibra_play_work(struct work_struct
*work
)
49 struct vibra_info
*info
= container_of(work
, struct vibra_info
,
52 if (info
->strength
&& !info
->enabled
)
53 sc27xx_vibra_set(info
, true);
54 else if (info
->strength
== 0 && info
->enabled
)
55 sc27xx_vibra_set(info
, false);
58 static int sc27xx_vibra_play(struct input_dev
*input
, void *data
,
59 struct ff_effect
*effect
)
61 struct vibra_info
*info
= input_get_drvdata(input
);
63 info
->strength
= effect
->u
.rumble
.weak_magnitude
;
64 schedule_work(&info
->play_work
);
69 static void sc27xx_vibra_close(struct input_dev
*input
)
71 struct vibra_info
*info
= input_get_drvdata(input
);
73 cancel_work_sync(&info
->play_work
);
75 sc27xx_vibra_set(info
, false);
78 static int sc27xx_vibra_probe(struct platform_device
*pdev
)
80 struct vibra_info
*info
;
83 info
= devm_kzalloc(&pdev
->dev
, sizeof(*info
), GFP_KERNEL
);
87 info
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
89 dev_err(&pdev
->dev
, "failed to get vibrator regmap.\n");
93 error
= device_property_read_u32(&pdev
->dev
, "reg", &info
->base
);
95 dev_err(&pdev
->dev
, "failed to get vibrator base address.\n");
99 info
->input_dev
= devm_input_allocate_device(&pdev
->dev
);
100 if (!info
->input_dev
) {
101 dev_err(&pdev
->dev
, "failed to allocate input device.\n");
105 info
->input_dev
->name
= "sc27xx:vibrator";
106 info
->input_dev
->id
.version
= 0;
107 info
->input_dev
->close
= sc27xx_vibra_close
;
109 input_set_drvdata(info
->input_dev
, info
);
110 input_set_capability(info
->input_dev
, EV_FF
, FF_RUMBLE
);
111 INIT_WORK(&info
->play_work
, sc27xx_vibra_play_work
);
112 info
->enabled
= false;
114 error
= sc27xx_vibra_hw_init(info
);
116 dev_err(&pdev
->dev
, "failed to initialize the vibrator.\n");
120 error
= input_ff_create_memless(info
->input_dev
, NULL
,
123 dev_err(&pdev
->dev
, "failed to register vibrator to FF.\n");
127 error
= input_register_device(info
->input_dev
);
129 dev_err(&pdev
->dev
, "failed to register input device.\n");
136 static const struct of_device_id sc27xx_vibra_of_match
[] = {
137 { .compatible
= "sprd,sc2731-vibrator", },
140 MODULE_DEVICE_TABLE(of
, sc27xx_vibra_of_match
);
142 static struct platform_driver sc27xx_vibra_driver
= {
144 .name
= "sc27xx-vibrator",
145 .of_match_table
= sc27xx_vibra_of_match
,
147 .probe
= sc27xx_vibra_probe
,
150 module_platform_driver(sc27xx_vibra_driver
);
152 MODULE_DESCRIPTION("Spreadtrum SC27xx Vibrator Driver");
153 MODULE_LICENSE("GPL v2");
154 MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");