Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018 Spreadtrum Communications Inc.
0004  */
0005 
0006 #include <linux/device.h>
0007 #include <linux/input.h>
0008 #include <linux/mod_devicetable.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/property.h>
0012 #include <linux/regmap.h>
0013 #include <linux/workqueue.h>
0014 
0015 #define CUR_DRV_CAL_SEL         GENMASK(13, 12)
0016 #define SLP_LDOVIBR_PD_EN       BIT(9)
0017 #define LDO_VIBR_PD         BIT(8)
0018 #define SC2730_CUR_DRV_CAL_SEL      0
0019 #define SC2730_SLP_LDOVIBR_PD_EN    BIT(14)
0020 #define SC2730_LDO_VIBR_PD      BIT(13)
0021 
0022 struct sc27xx_vibra_data {
0023     u32 cur_drv_cal_sel;
0024     u32 slp_pd_en;
0025     u32 ldo_pd;
0026 };
0027 
0028 struct vibra_info {
0029     struct input_dev    *input_dev;
0030     struct work_struct  play_work;
0031     struct regmap       *regmap;
0032     const struct sc27xx_vibra_data *data;
0033     u32         base;
0034     u32         strength;
0035     bool            enabled;
0036 };
0037 
0038 static const struct sc27xx_vibra_data sc2731_data = {
0039     .cur_drv_cal_sel = CUR_DRV_CAL_SEL,
0040     .slp_pd_en = SLP_LDOVIBR_PD_EN,
0041     .ldo_pd = LDO_VIBR_PD,
0042 };
0043 
0044 static const struct sc27xx_vibra_data sc2730_data = {
0045     .cur_drv_cal_sel = SC2730_CUR_DRV_CAL_SEL,
0046     .slp_pd_en = SC2730_SLP_LDOVIBR_PD_EN,
0047     .ldo_pd = SC2730_LDO_VIBR_PD,
0048 };
0049 
0050 static const struct sc27xx_vibra_data sc2721_data = {
0051     .cur_drv_cal_sel = CUR_DRV_CAL_SEL,
0052     .slp_pd_en = SLP_LDOVIBR_PD_EN,
0053     .ldo_pd = LDO_VIBR_PD,
0054 };
0055 
0056 static void sc27xx_vibra_set(struct vibra_info *info, bool on)
0057 {
0058     const struct sc27xx_vibra_data *data = info->data;
0059     if (on) {
0060         regmap_update_bits(info->regmap, info->base, data->ldo_pd, 0);
0061         regmap_update_bits(info->regmap, info->base,
0062                    data->slp_pd_en, 0);
0063         info->enabled = true;
0064     } else {
0065         regmap_update_bits(info->regmap, info->base, data->ldo_pd,
0066                    data->ldo_pd);
0067         regmap_update_bits(info->regmap, info->base,
0068                    data->slp_pd_en, data->slp_pd_en);
0069         info->enabled = false;
0070     }
0071 }
0072 
0073 static int sc27xx_vibra_hw_init(struct vibra_info *info)
0074 {
0075     const struct sc27xx_vibra_data *data = info->data;
0076 
0077     if (!data->cur_drv_cal_sel)
0078         return 0;
0079 
0080     return regmap_update_bits(info->regmap, info->base,
0081                   data->cur_drv_cal_sel, 0);
0082 }
0083 
0084 static void sc27xx_vibra_play_work(struct work_struct *work)
0085 {
0086     struct vibra_info *info = container_of(work, struct vibra_info,
0087                            play_work);
0088 
0089     if (info->strength && !info->enabled)
0090         sc27xx_vibra_set(info, true);
0091     else if (info->strength == 0 && info->enabled)
0092         sc27xx_vibra_set(info, false);
0093 }
0094 
0095 static int sc27xx_vibra_play(struct input_dev *input, void *data,
0096                  struct ff_effect *effect)
0097 {
0098     struct vibra_info *info = input_get_drvdata(input);
0099 
0100     info->strength = effect->u.rumble.weak_magnitude;
0101     schedule_work(&info->play_work);
0102 
0103     return 0;
0104 }
0105 
0106 static void sc27xx_vibra_close(struct input_dev *input)
0107 {
0108     struct vibra_info *info = input_get_drvdata(input);
0109 
0110     cancel_work_sync(&info->play_work);
0111     if (info->enabled)
0112         sc27xx_vibra_set(info, false);
0113 }
0114 
0115 static int sc27xx_vibra_probe(struct platform_device *pdev)
0116 {
0117     struct vibra_info *info;
0118     const struct sc27xx_vibra_data *data;
0119     int error;
0120 
0121     data = device_get_match_data(&pdev->dev);
0122     if (!data) {
0123         dev_err(&pdev->dev, "no matching driver data found\n");
0124         return -EINVAL;
0125     }
0126 
0127     info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
0128     if (!info)
0129         return -ENOMEM;
0130 
0131     info->regmap = dev_get_regmap(pdev->dev.parent, NULL);
0132     if (!info->regmap) {
0133         dev_err(&pdev->dev, "failed to get vibrator regmap.\n");
0134         return -ENODEV;
0135     }
0136 
0137     error = device_property_read_u32(&pdev->dev, "reg", &info->base);
0138     if (error) {
0139         dev_err(&pdev->dev, "failed to get vibrator base address.\n");
0140         return error;
0141     }
0142 
0143     info->input_dev = devm_input_allocate_device(&pdev->dev);
0144     if (!info->input_dev) {
0145         dev_err(&pdev->dev, "failed to allocate input device.\n");
0146         return -ENOMEM;
0147     }
0148 
0149     info->input_dev->name = "sc27xx:vibrator";
0150     info->input_dev->id.version = 0;
0151     info->input_dev->close = sc27xx_vibra_close;
0152     info->data = data;
0153 
0154     input_set_drvdata(info->input_dev, info);
0155     input_set_capability(info->input_dev, EV_FF, FF_RUMBLE);
0156     INIT_WORK(&info->play_work, sc27xx_vibra_play_work);
0157     info->enabled = false;
0158 
0159     error = sc27xx_vibra_hw_init(info);
0160     if (error) {
0161         dev_err(&pdev->dev, "failed to initialize the vibrator.\n");
0162         return error;
0163     }
0164 
0165     error = input_ff_create_memless(info->input_dev, NULL,
0166                     sc27xx_vibra_play);
0167     if (error) {
0168         dev_err(&pdev->dev, "failed to register vibrator to FF.\n");
0169         return error;
0170     }
0171 
0172     error = input_register_device(info->input_dev);
0173     if (error) {
0174         dev_err(&pdev->dev, "failed to register input device.\n");
0175         return error;
0176     }
0177 
0178     return 0;
0179 }
0180 
0181 static const struct of_device_id sc27xx_vibra_of_match[] = {
0182     { .compatible = "sprd,sc2721-vibrator", .data = &sc2721_data },
0183     { .compatible = "sprd,sc2730-vibrator", .data = &sc2730_data },
0184     { .compatible = "sprd,sc2731-vibrator", .data = &sc2731_data },
0185     {}
0186 };
0187 MODULE_DEVICE_TABLE(of, sc27xx_vibra_of_match);
0188 
0189 static struct platform_driver sc27xx_vibra_driver = {
0190     .driver = {
0191         .name = "sc27xx-vibrator",
0192         .of_match_table = sc27xx_vibra_of_match,
0193     },
0194     .probe = sc27xx_vibra_probe,
0195 };
0196 
0197 module_platform_driver(sc27xx_vibra_driver);
0198 
0199 MODULE_DESCRIPTION("Spreadtrum SC27xx Vibrator Driver");
0200 MODULE_LICENSE("GPL v2");
0201 MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");