1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Spreadtrum Communications Inc.
6 #include <linux/device.h>
7 #include <linux/input.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/property.h>
12 #include <linux/regmap.h>
13 #include <linux/workqueue.h>
15 #define CUR_DRV_CAL_SEL GENMASK(13, 12)
16 #define SLP_LDOVIBR_PD_EN BIT(9)
17 #define LDO_VIBR_PD BIT(8)
18 #define SC2730_CUR_DRV_CAL_SEL 0
19 #define SC2730_SLP_LDOVIBR_PD_EN BIT(14)
20 #define SC2730_LDO_VIBR_PD BIT(13)
22 struct sc27xx_vibra_data
{
29 struct input_dev
*input_dev
;
30 struct work_struct play_work
;
31 struct regmap
*regmap
;
32 const struct sc27xx_vibra_data
*data
;
38 static const struct sc27xx_vibra_data sc2731_data
= {
39 .cur_drv_cal_sel
= CUR_DRV_CAL_SEL
,
40 .slp_pd_en
= SLP_LDOVIBR_PD_EN
,
41 .ldo_pd
= LDO_VIBR_PD
,
44 static const struct sc27xx_vibra_data sc2730_data
= {
45 .cur_drv_cal_sel
= SC2730_CUR_DRV_CAL_SEL
,
46 .slp_pd_en
= SC2730_SLP_LDOVIBR_PD_EN
,
47 .ldo_pd
= SC2730_LDO_VIBR_PD
,
50 static const struct sc27xx_vibra_data sc2721_data
= {
51 .cur_drv_cal_sel
= CUR_DRV_CAL_SEL
,
52 .slp_pd_en
= SLP_LDOVIBR_PD_EN
,
53 .ldo_pd
= LDO_VIBR_PD
,
56 static void sc27xx_vibra_set(struct vibra_info
*info
, bool on
)
58 const struct sc27xx_vibra_data
*data
= info
->data
;
60 regmap_update_bits(info
->regmap
, info
->base
, data
->ldo_pd
, 0);
61 regmap_update_bits(info
->regmap
, info
->base
,
65 regmap_update_bits(info
->regmap
, info
->base
, data
->ldo_pd
,
67 regmap_update_bits(info
->regmap
, info
->base
,
68 data
->slp_pd_en
, data
->slp_pd_en
);
69 info
->enabled
= false;
73 static int sc27xx_vibra_hw_init(struct vibra_info
*info
)
75 const struct sc27xx_vibra_data
*data
= info
->data
;
77 if (!data
->cur_drv_cal_sel
)
80 return regmap_update_bits(info
->regmap
, info
->base
,
81 data
->cur_drv_cal_sel
, 0);
84 static void sc27xx_vibra_play_work(struct work_struct
*work
)
86 struct vibra_info
*info
= container_of(work
, struct vibra_info
,
89 if (info
->strength
&& !info
->enabled
)
90 sc27xx_vibra_set(info
, true);
91 else if (info
->strength
== 0 && info
->enabled
)
92 sc27xx_vibra_set(info
, false);
95 static int sc27xx_vibra_play(struct input_dev
*input
, void *data
,
96 struct ff_effect
*effect
)
98 struct vibra_info
*info
= input_get_drvdata(input
);
100 info
->strength
= effect
->u
.rumble
.weak_magnitude
;
101 schedule_work(&info
->play_work
);
106 static void sc27xx_vibra_close(struct input_dev
*input
)
108 struct vibra_info
*info
= input_get_drvdata(input
);
110 cancel_work_sync(&info
->play_work
);
112 sc27xx_vibra_set(info
, false);
115 static int sc27xx_vibra_probe(struct platform_device
*pdev
)
117 struct vibra_info
*info
;
118 const struct sc27xx_vibra_data
*data
;
121 data
= device_get_match_data(&pdev
->dev
);
123 dev_err(&pdev
->dev
, "no matching driver data found\n");
127 info
= devm_kzalloc(&pdev
->dev
, sizeof(*info
), GFP_KERNEL
);
131 info
->regmap
= dev_get_regmap(pdev
->dev
.parent
, NULL
);
133 dev_err(&pdev
->dev
, "failed to get vibrator regmap.\n");
137 error
= device_property_read_u32(&pdev
->dev
, "reg", &info
->base
);
139 dev_err(&pdev
->dev
, "failed to get vibrator base address.\n");
143 info
->input_dev
= devm_input_allocate_device(&pdev
->dev
);
144 if (!info
->input_dev
) {
145 dev_err(&pdev
->dev
, "failed to allocate input device.\n");
149 info
->input_dev
->name
= "sc27xx:vibrator";
150 info
->input_dev
->id
.version
= 0;
151 info
->input_dev
->close
= sc27xx_vibra_close
;
154 input_set_drvdata(info
->input_dev
, info
);
155 input_set_capability(info
->input_dev
, EV_FF
, FF_RUMBLE
);
156 INIT_WORK(&info
->play_work
, sc27xx_vibra_play_work
);
157 info
->enabled
= false;
159 error
= sc27xx_vibra_hw_init(info
);
161 dev_err(&pdev
->dev
, "failed to initialize the vibrator.\n");
165 error
= input_ff_create_memless(info
->input_dev
, NULL
,
168 dev_err(&pdev
->dev
, "failed to register vibrator to FF.\n");
172 error
= input_register_device(info
->input_dev
);
174 dev_err(&pdev
->dev
, "failed to register input device.\n");
181 static const struct of_device_id sc27xx_vibra_of_match
[] = {
182 { .compatible
= "sprd,sc2721-vibrator", .data
= &sc2721_data
},
183 { .compatible
= "sprd,sc2730-vibrator", .data
= &sc2730_data
},
184 { .compatible
= "sprd,sc2731-vibrator", .data
= &sc2731_data
},
187 MODULE_DEVICE_TABLE(of
, sc27xx_vibra_of_match
);
189 static struct platform_driver sc27xx_vibra_driver
= {
191 .name
= "sc27xx-vibrator",
192 .of_match_table
= sc27xx_vibra_of_match
,
194 .probe
= sc27xx_vibra_probe
,
197 module_platform_driver(sc27xx_vibra_driver
);
199 MODULE_DESCRIPTION("Spreadtrum SC27xx Vibrator Driver");
200 MODULE_LICENSE("GPL v2");
201 MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");