root/drivers/input/misc/twl4030-vibra.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vibra_disable_leds
  2. vibra_enable
  3. vibra_disable
  4. vibra_play_work
  5. vibra_play
  6. twl4030_vibra_close
  7. twl4030_vibra_suspend
  8. twl4030_vibra_resume
  9. twl4030_vibra_check_coexist
  10. twl4030_vibra_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * twl4030-vibra.c - TWL4030 Vibrator driver
   4  *
   5  * Copyright (C) 2008-2010 Nokia Corporation
   6  *
   7  * Written by Henrik Saari <henrik.saari@nokia.com>
   8  * Updates by Felipe Balbi <felipe.balbi@nokia.com>
   9  * Input by Jari Vanhala <ext-jari.vanhala@nokia.com>
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/jiffies.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/of.h>
  16 #include <linux/workqueue.h>
  17 #include <linux/mfd/twl.h>
  18 #include <linux/mfd/twl4030-audio.h>
  19 #include <linux/input.h>
  20 #include <linux/slab.h>
  21 
  22 /* MODULE ID2 */
  23 #define LEDEN           0x00
  24 
  25 /* ForceFeedback */
  26 #define EFFECT_DIR_180_DEG      0x8000 /* range is 0 - 0xFFFF */
  27 
  28 struct vibra_info {
  29         struct device           *dev;
  30         struct input_dev        *input_dev;
  31 
  32         struct work_struct      play_work;
  33 
  34         bool                    enabled;
  35         int                     speed;
  36         int                     direction;
  37 
  38         bool                    coexist;
  39 };
  40 
  41 static void vibra_disable_leds(void)
  42 {
  43         u8 reg;
  44 
  45         /* Disable LEDA & LEDB, cannot be used with vibra (PWM) */
  46         twl_i2c_read_u8(TWL4030_MODULE_LED, &reg, LEDEN);
  47         reg &= ~0x03;
  48         twl_i2c_write_u8(TWL4030_MODULE_LED, LEDEN, reg);
  49 }
  50 
  51 /* Powers H-Bridge and enables audio clk */
  52 static void vibra_enable(struct vibra_info *info)
  53 {
  54         u8 reg;
  55 
  56         twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
  57 
  58         /* turn H-Bridge on */
  59         twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
  60                         &reg, TWL4030_REG_VIBRA_CTL);
  61         twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
  62                          (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
  63 
  64         twl4030_audio_enable_resource(TWL4030_AUDIO_RES_APLL);
  65 
  66         info->enabled = true;
  67 }
  68 
  69 static void vibra_disable(struct vibra_info *info)
  70 {
  71         u8 reg;
  72 
  73         /* Power down H-Bridge */
  74         twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
  75                         &reg, TWL4030_REG_VIBRA_CTL);
  76         twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
  77                          (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
  78 
  79         twl4030_audio_disable_resource(TWL4030_AUDIO_RES_APLL);
  80         twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
  81 
  82         info->enabled = false;
  83 }
  84 
  85 static void vibra_play_work(struct work_struct *work)
  86 {
  87         struct vibra_info *info = container_of(work,
  88                         struct vibra_info, play_work);
  89         int dir;
  90         int pwm;
  91         u8 reg;
  92 
  93         dir = info->direction;
  94         pwm = info->speed;
  95 
  96         twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
  97                         &reg, TWL4030_REG_VIBRA_CTL);
  98         if (pwm && (!info->coexist || !(reg & TWL4030_VIBRA_SEL))) {
  99 
 100                 if (!info->enabled)
 101                         vibra_enable(info);
 102 
 103                 /* set vibra rotation direction */
 104                 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
 105                                 &reg, TWL4030_REG_VIBRA_CTL);
 106                 reg = (dir) ? (reg | TWL4030_VIBRA_DIR) :
 107                         (reg & ~TWL4030_VIBRA_DIR);
 108                 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
 109                                  reg, TWL4030_REG_VIBRA_CTL);
 110 
 111                 /* set PWM, 1 = max, 255 = min */
 112                 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
 113                                  256 - pwm, TWL4030_REG_VIBRA_SET);
 114         } else {
 115                 if (info->enabled)
 116                         vibra_disable(info);
 117         }
 118 }
 119 
 120 /*** Input/ForceFeedback ***/
 121 
 122 static int vibra_play(struct input_dev *input, void *data,
 123                       struct ff_effect *effect)
 124 {
 125         struct vibra_info *info = input_get_drvdata(input);
 126 
 127         info->speed = effect->u.rumble.strong_magnitude >> 8;
 128         if (!info->speed)
 129                 info->speed = effect->u.rumble.weak_magnitude >> 9;
 130         info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
 131         schedule_work(&info->play_work);
 132         return 0;
 133 }
 134 
 135 static void twl4030_vibra_close(struct input_dev *input)
 136 {
 137         struct vibra_info *info = input_get_drvdata(input);
 138 
 139         cancel_work_sync(&info->play_work);
 140 
 141         if (info->enabled)
 142                 vibra_disable(info);
 143 }
 144 
 145 /*** Module ***/
 146 static int __maybe_unused twl4030_vibra_suspend(struct device *dev)
 147 {
 148         struct platform_device *pdev = to_platform_device(dev);
 149         struct vibra_info *info = platform_get_drvdata(pdev);
 150 
 151         if (info->enabled)
 152                 vibra_disable(info);
 153 
 154         return 0;
 155 }
 156 
 157 static int __maybe_unused twl4030_vibra_resume(struct device *dev)
 158 {
 159         vibra_disable_leds();
 160         return 0;
 161 }
 162 
 163 static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
 164                          twl4030_vibra_suspend, twl4030_vibra_resume);
 165 
 166 static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
 167                               struct device_node *parent)
 168 {
 169         struct device_node *node;
 170 
 171         if (pdata && pdata->coexist)
 172                 return true;
 173 
 174         node = of_get_child_by_name(parent, "codec");
 175         if (node) {
 176                 of_node_put(node);
 177                 return true;
 178         }
 179 
 180         return false;
 181 }
 182 
 183 static int twl4030_vibra_probe(struct platform_device *pdev)
 184 {
 185         struct twl4030_vibra_data *pdata = dev_get_platdata(&pdev->dev);
 186         struct device_node *twl4030_core_node = pdev->dev.parent->of_node;
 187         struct vibra_info *info;
 188         int ret;
 189 
 190         if (!pdata && !twl4030_core_node) {
 191                 dev_dbg(&pdev->dev, "platform_data not available\n");
 192                 return -EINVAL;
 193         }
 194 
 195         info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 196         if (!info)
 197                 return -ENOMEM;
 198 
 199         info->dev = &pdev->dev;
 200         info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
 201         INIT_WORK(&info->play_work, vibra_play_work);
 202 
 203         info->input_dev = devm_input_allocate_device(&pdev->dev);
 204         if (info->input_dev == NULL) {
 205                 dev_err(&pdev->dev, "couldn't allocate input device\n");
 206                 return -ENOMEM;
 207         }
 208 
 209         input_set_drvdata(info->input_dev, info);
 210 
 211         info->input_dev->name = "twl4030:vibrator";
 212         info->input_dev->id.version = 1;
 213         info->input_dev->close = twl4030_vibra_close;
 214         __set_bit(FF_RUMBLE, info->input_dev->ffbit);
 215 
 216         ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
 217         if (ret < 0) {
 218                 dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
 219                 return ret;
 220         }
 221 
 222         ret = input_register_device(info->input_dev);
 223         if (ret < 0) {
 224                 dev_dbg(&pdev->dev, "couldn't register input device\n");
 225                 goto err_iff;
 226         }
 227 
 228         vibra_disable_leds();
 229 
 230         platform_set_drvdata(pdev, info);
 231         return 0;
 232 
 233 err_iff:
 234         input_ff_destroy(info->input_dev);
 235         return ret;
 236 }
 237 
 238 static struct platform_driver twl4030_vibra_driver = {
 239         .probe          = twl4030_vibra_probe,
 240         .driver         = {
 241                 .name   = "twl4030-vibra",
 242                 .pm     = &twl4030_vibra_pm_ops,
 243         },
 244 };
 245 module_platform_driver(twl4030_vibra_driver);
 246 
 247 MODULE_ALIAS("platform:twl4030-vibra");
 248 MODULE_DESCRIPTION("TWL4030 Vibra driver");
 249 MODULE_LICENSE("GPL");
 250 MODULE_AUTHOR("Nokia Corporation");

/* [<][>][^][v][top][bottom][index][help] */