1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2018 Spreadtrum Communications Inc. 4 */ 5 6 #include <linux/device.h> 7 #include <linux/input.h> 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <linux/property.h> 11 #include <linux/regmap.h> 12 #include <linux/workqueue.h> 13 14 #define CUR_DRV_CAL_SEL GENMASK(13, 12) 15 #define SLP_LDOVIBR_PD_EN BIT(9) 16 #define LDO_VIBR_PD BIT(8) 17 #define SC2730_CUR_DRV_CAL_SEL 0 18 #define SC2730_SLP_LDOVIBR_PD_EN BIT(14) 19 #define SC2730_LDO_VIBR_PD BIT(13) 20 21 struct sc27xx_vibra_data { 22 u32 cur_drv_cal_sel; 23 u32 slp_pd_en; 24 u32 ldo_pd; 25 }; 26 27 struct vibra_info { 28 struct input_dev *input_dev; 29 struct work_struct play_work; 30 struct regmap *regmap; 31 const struct sc27xx_vibra_data *data; 32 u32 base; 33 u32 strength; 34 bool enabled; 35 }; 36 37 static const struct sc27xx_vibra_data sc2731_data = { 38 .cur_drv_cal_sel = CUR_DRV_CAL_SEL, 39 .slp_pd_en = SLP_LDOVIBR_PD_EN, 40 .ldo_pd = LDO_VIBR_PD, 41 }; 42 43 static const struct sc27xx_vibra_data sc2730_data = { 44 .cur_drv_cal_sel = SC2730_CUR_DRV_CAL_SEL, 45 .slp_pd_en = SC2730_SLP_LDOVIBR_PD_EN, 46 .ldo_pd = SC2730_LDO_VIBR_PD, 47 }; 48 49 static const struct sc27xx_vibra_data sc2721_data = { 50 .cur_drv_cal_sel = CUR_DRV_CAL_SEL, 51 .slp_pd_en = SLP_LDOVIBR_PD_EN, 52 .ldo_pd = LDO_VIBR_PD, 53 }; 54 55 static void sc27xx_vibra_set(struct vibra_info *info, bool on) 56 { 57 const struct sc27xx_vibra_data *data = info->data; 58 if (on) { 59 regmap_update_bits(info->regmap, info->base, data->ldo_pd, 0); 60 regmap_update_bits(info->regmap, info->base, 61 data->slp_pd_en, 0); 62 info->enabled = true; 63 } else { 64 regmap_update_bits(info->regmap, info->base, data->ldo_pd, 65 data->ldo_pd); 66 regmap_update_bits(info->regmap, info->base, 67 data->slp_pd_en, data->slp_pd_en); 68 info->enabled = false; 69 } 70 } 71 72 static int sc27xx_vibra_hw_init(struct vibra_info *info) 73 { 74 const struct sc27xx_vibra_data *data = info->data; 75 76 if (!data->cur_drv_cal_sel) 77 return 0; 78 79 return regmap_update_bits(info->regmap, info->base, 80 data->cur_drv_cal_sel, 0); 81 } 82 83 static void sc27xx_vibra_play_work(struct work_struct *work) 84 { 85 struct vibra_info *info = container_of(work, struct vibra_info, 86 play_work); 87 88 if (info->strength && !info->enabled) 89 sc27xx_vibra_set(info, true); 90 else if (info->strength == 0 && info->enabled) 91 sc27xx_vibra_set(info, false); 92 } 93 94 static int sc27xx_vibra_play(struct input_dev *input, void *data, 95 struct ff_effect *effect) 96 { 97 struct vibra_info *info = input_get_drvdata(input); 98 99 info->strength = effect->u.rumble.weak_magnitude; 100 schedule_work(&info->play_work); 101 102 return 0; 103 } 104 105 static void sc27xx_vibra_close(struct input_dev *input) 106 { 107 struct vibra_info *info = input_get_drvdata(input); 108 109 cancel_work_sync(&info->play_work); 110 if (info->enabled) 111 sc27xx_vibra_set(info, false); 112 } 113 114 static int sc27xx_vibra_probe(struct platform_device *pdev) 115 { 116 struct vibra_info *info; 117 const struct sc27xx_vibra_data *data; 118 int error; 119 120 data = device_get_match_data(&pdev->dev); 121 if (!data) { 122 dev_err(&pdev->dev, "no matching driver data found\n"); 123 return -EINVAL; 124 } 125 126 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 127 if (!info) 128 return -ENOMEM; 129 130 info->regmap = dev_get_regmap(pdev->dev.parent, NULL); 131 if (!info->regmap) { 132 dev_err(&pdev->dev, "failed to get vibrator regmap.\n"); 133 return -ENODEV; 134 } 135 136 error = device_property_read_u32(&pdev->dev, "reg", &info->base); 137 if (error) { 138 dev_err(&pdev->dev, "failed to get vibrator base address.\n"); 139 return error; 140 } 141 142 info->input_dev = devm_input_allocate_device(&pdev->dev); 143 if (!info->input_dev) { 144 dev_err(&pdev->dev, "failed to allocate input device.\n"); 145 return -ENOMEM; 146 } 147 148 info->input_dev->name = "sc27xx:vibrator"; 149 info->input_dev->id.version = 0; 150 info->input_dev->close = sc27xx_vibra_close; 151 info->data = data; 152 153 input_set_drvdata(info->input_dev, info); 154 input_set_capability(info->input_dev, EV_FF, FF_RUMBLE); 155 INIT_WORK(&info->play_work, sc27xx_vibra_play_work); 156 info->enabled = false; 157 158 error = sc27xx_vibra_hw_init(info); 159 if (error) { 160 dev_err(&pdev->dev, "failed to initialize the vibrator.\n"); 161 return error; 162 } 163 164 error = input_ff_create_memless(info->input_dev, NULL, 165 sc27xx_vibra_play); 166 if (error) { 167 dev_err(&pdev->dev, "failed to register vibrator to FF.\n"); 168 return error; 169 } 170 171 error = input_register_device(info->input_dev); 172 if (error) { 173 dev_err(&pdev->dev, "failed to register input device.\n"); 174 return error; 175 } 176 177 return 0; 178 } 179 180 static const struct of_device_id sc27xx_vibra_of_match[] = { 181 { .compatible = "sprd,sc2721-vibrator", .data = &sc2721_data }, 182 { .compatible = "sprd,sc2730-vibrator", .data = &sc2730_data }, 183 { .compatible = "sprd,sc2731-vibrator", .data = &sc2731_data }, 184 {} 185 }; 186 MODULE_DEVICE_TABLE(of, sc27xx_vibra_of_match); 187 188 static struct platform_driver sc27xx_vibra_driver = { 189 .driver = { 190 .name = "sc27xx-vibrator", 191 .of_match_table = sc27xx_vibra_of_match, 192 }, 193 .probe = sc27xx_vibra_probe, 194 }; 195 196 module_platform_driver(sc27xx_vibra_driver); 197 198 MODULE_DESCRIPTION("Spreadtrum SC27xx Vibrator Driver"); 199 MODULE_LICENSE("GPL v2"); 200 MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>"); 201