123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- /*
- * Copyright (C) 2009 Samsung Electronics
- * Kyungmin Park <kyungmin.park@samsung.com>
- *
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #define pr_fmt(fmt) "%s: " fmt, __func__
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/i2c.h>
- #include <linux/gpio.h>
- #include <linux/workqueue.h>
- #include <linux/delay.h>
- #include <linux/pwm.h>
- #include <linux/input.h>
- #include <linux/slab.h>
- #include <linux/pm.h>
- #include <linux/i2c/isa1200.h>
- #define ISA1200_HCTRL0 0x30
- #define HCTRL0_MODE_CTRL_BIT (3)
- #define HCTRL0_OVERDRIVE_HIGH_BIT (5)
- #define HCTRL0_OVERDRIVE_EN_BIT (6)
- #define HCTRL0_HAP_EN (7)
- #define HCTRL0_RESET 0x01
- #define HCTRL1_RESET 0x4B
- #define ISA1200_HCTRL1 0x31
- #define HCTRL1_SMART_ENABLE_BIT (3)
- #define HCTRL1_ERM_BIT (5)
- #define HCTRL1_EXT_CLK_ENABLE_BIT (7)
- #define ISA1200_HCTRL5 0x35
- #define HCTRL5_VIB_STRT 0xD5
- #define HCTRL5_VIB_STOP 0x6B
- #define DIVIDER_128 (128)
- #define DIVIDER_1024 (1024)
- #define DIVIDE_SHIFTER_128 (7)
- #define FREQ_22400 (22400)
- #define FREQ_172600 (172600)
- #define POR_DELAY_USEC 250
- struct isa1200_chip {
- const struct isa1200_platform_data *pdata;
- struct i2c_client *client;
- struct input_dev *input_device;
- struct pwm_device *pwm;
- unsigned int period_ns;
- unsigned int state;
- struct work_struct work;
- };
- static void isa1200_vib_set(struct isa1200_chip *haptic, int enable)
- {
- int rc;
- if (enable) {
- if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
- int period_us = haptic->period_ns / NSEC_PER_USEC;
- rc = pwm_config(haptic->pwm,
- (period_us * haptic->pdata->duty) / 100,
- period_us);
- if (rc < 0)
- pr_err("pwm_config fail\n");
- rc = pwm_enable(haptic->pwm);
- if (rc < 0)
- pr_err("pwm_enable fail\n");
- } else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
- rc = i2c_smbus_write_byte_data(haptic->client,
- ISA1200_HCTRL5,
- HCTRL5_VIB_STRT);
- if (rc < 0)
- pr_err("start vibration fail\n");
- }
- } else {
- if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
- pwm_disable(haptic->pwm);
- else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
- rc = i2c_smbus_write_byte_data(haptic->client,
- ISA1200_HCTRL5,
- HCTRL5_VIB_STOP);
- if (rc < 0)
- pr_err("stop vibration fail\n");
- }
- }
- }
- static int isa1200_setup(struct i2c_client *client)
- {
- struct isa1200_chip *haptic = i2c_get_clientdata(client);
- int value, temp, rc;
- gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
- udelay(POR_DELAY_USEC);
- gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 1);
- value = (haptic->pdata->smart_en << HCTRL1_SMART_ENABLE_BIT) |
- (haptic->pdata->is_erm << HCTRL1_ERM_BIT) |
- (haptic->pdata->ext_clk_en << HCTRL1_EXT_CLK_ENABLE_BIT);
- rc = i2c_smbus_write_byte_data(client, ISA1200_HCTRL1, value);
- if (rc < 0) {
- pr_err("i2c write failure\n");
- return rc;
- }
- if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
- temp = haptic->pdata->pwm_fd.pwm_div;
- if (temp < DIVIDER_128 || temp > DIVIDER_1024 ||
- temp % DIVIDER_128) {
- pr_err("Invalid divider\n");
- rc = -EINVAL;
- goto reset_hctrl1;
- }
- value = ((temp >> DIVIDE_SHIFTER_128) - 1);
- } else if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
- temp = haptic->pdata->pwm_fd.pwm_freq;
- if (temp < FREQ_22400 || temp > FREQ_172600 ||
- temp % FREQ_22400) {
- pr_err("Invalid frequency\n");
- rc = -EINVAL;
- goto reset_hctrl1;
- }
- value = ((temp / FREQ_22400) - 1);
- haptic->period_ns = NSEC_PER_SEC / temp;
- }
- value |= (haptic->pdata->mode_ctrl << HCTRL0_MODE_CTRL_BIT) |
- (haptic->pdata->overdrive_high << HCTRL0_OVERDRIVE_HIGH_BIT) |
- (haptic->pdata->overdrive_en << HCTRL0_OVERDRIVE_EN_BIT) |
- (haptic->pdata->chip_en << HCTRL0_HAP_EN);
- rc = i2c_smbus_write_byte_data(client, ISA1200_HCTRL0, value);
- if (rc < 0) {
- pr_err("i2c write failure\n");
- goto reset_hctrl1;
- }
- return 0;
- reset_hctrl1:
- i2c_smbus_write_byte_data(client, ISA1200_HCTRL1,
- HCTRL1_RESET);
- return rc;
- }
- static void isa1200_worker(struct work_struct *work)
- {
- struct isa1200_chip *haptic;
- haptic = container_of(work, struct isa1200_chip, work);
- isa1200_vib_set(haptic, !!haptic->state);
- }
- static int isa1200_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
- {
- struct isa1200_chip *haptic = input_get_drvdata(dev);
- /* support basic vibration */
- haptic->state = effect->u.rumble.strong_magnitude >> 8;
- if (!haptic->state)
- haptic->state = effect->u.rumble.weak_magnitude >> 9;
- schedule_work(&haptic->work);
- return 0;
- }
- #ifdef CONFIG_PM
- static int isa1200_suspend(struct device *dev)
- {
- struct isa1200_chip *haptic = dev_get_drvdata(dev);
- int rc;
- cancel_work_sync(&haptic->work);
- /* turn-off current vibration */
- isa1200_vib_set(haptic, 0);
- if (haptic->pdata->power_on) {
- rc = haptic->pdata->power_on(0);
- if (rc) {
- pr_err("power-down failed\n");
- return rc;
- }
- }
- return 0;
- }
- static int isa1200_resume(struct device *dev)
- {
- struct isa1200_chip *haptic = dev_get_drvdata(dev);
- int rc;
- if (haptic->pdata->power_on) {
- rc = haptic->pdata->power_on(1);
- if (rc) {
- pr_err("power-up failed\n");
- return rc;
- }
- }
- isa1200_setup(haptic->client);
- return 0;
- }
- #else
- #define isa1200_suspend NULL
- #define isa1200_resume NULL
- #endif
- static int isa1200_open(struct input_dev *dev)
- {
- struct isa1200_chip *haptic = input_get_drvdata(dev);
- int rc;
- /* device setup */
- if (haptic->pdata->dev_setup) {
- rc = haptic->pdata->dev_setup(true);
- if (rc < 0) {
- pr_err("setup failed!\n");
- return rc;
- }
- }
- /* power on */
- if (haptic->pdata->power_on) {
- rc = haptic->pdata->power_on(true);
- if (rc < 0) {
- pr_err("power failed\n");
- goto err_setup;
- }
- }
- /* request gpio */
- rc = gpio_is_valid(haptic->pdata->hap_en_gpio);
- if (rc) {
- rc = gpio_request(haptic->pdata->hap_en_gpio, "haptic_gpio");
- if (rc) {
- pr_err("gpio %d request failed\n",
- haptic->pdata->hap_en_gpio);
- goto err_power_on;
- }
- } else {
- pr_err("Invalid gpio %d\n",
- haptic->pdata->hap_en_gpio);
- goto err_power_on;
- }
- rc = gpio_direction_output(haptic->pdata->hap_en_gpio, 0);
- if (rc) {
- pr_err("gpio %d set direction failed\n",
- haptic->pdata->hap_en_gpio);
- goto err_gpio_free;
- }
- /* setup registers */
- rc = isa1200_setup(haptic->client);
- if (rc < 0) {
- pr_err("setup fail %d\n", rc);
- goto err_gpio_free;
- }
- if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
- haptic->pwm = pwm_request(haptic->pdata->pwm_ch_id,
- haptic->client->driver->id_table->name);
- if (IS_ERR(haptic->pwm)) {
- pr_err("pwm request failed\n");
- rc = PTR_ERR(haptic->pwm);
- goto err_reset_hctrl0;
- }
- }
- /* init workqeueue */
- INIT_WORK(&haptic->work, isa1200_worker);
- return 0;
- err_reset_hctrl0:
- i2c_smbus_write_byte_data(haptic->client, ISA1200_HCTRL0,
- HCTRL0_RESET);
- err_gpio_free:
- gpio_free(haptic->pdata->hap_en_gpio);
- err_power_on:
- if (haptic->pdata->power_on)
- haptic->pdata->power_on(0);
- err_setup:
- if (haptic->pdata->dev_setup)
- haptic->pdata->dev_setup(false);
- return rc;
- }
- static void isa1200_close(struct input_dev *dev)
- {
- struct isa1200_chip *haptic = input_get_drvdata(dev);
- /* turn-off current vibration */
- isa1200_vib_set(haptic, 0);
- if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
- pwm_free(haptic->pwm);
- gpio_free(haptic->pdata->hap_en_gpio);
- /* reset hardware registers */
- i2c_smbus_write_byte_data(haptic->client, ISA1200_HCTRL0,
- HCTRL0_RESET);
- i2c_smbus_write_byte_data(haptic->client, ISA1200_HCTRL1,
- HCTRL1_RESET);
- if (haptic->pdata->dev_setup)
- haptic->pdata->dev_setup(false);
- /* power-off the chip */
- if (haptic->pdata->power_on)
- haptic->pdata->power_on(0);
- }
- static int __devinit isa1200_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct isa1200_chip *haptic;
- int rc;
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_err("i2c is not supported\n");
- return -EIO;
- }
- if (!client->dev.platform_data) {
- pr_err("pdata is not avaiable\n");
- return -EINVAL;
- }
- haptic = kzalloc(sizeof(struct isa1200_chip), GFP_KERNEL);
- if (!haptic) {
- pr_err("no memory\n");
- return -ENOMEM;
- }
- haptic->pdata = client->dev.platform_data;
- haptic->client = client;
- i2c_set_clientdata(client, haptic);
- haptic->input_device = input_allocate_device();
- if (!haptic->input_device) {
- pr_err("input device alloc failed\n");
- rc = -ENOMEM;
- goto err_mem_alloc;
- }
- input_set_drvdata(haptic->input_device, haptic);
- haptic->input_device->name = haptic->pdata->name ? :
- "isa1200-ff-memless";
- haptic->input_device->dev.parent = &client->dev;
- input_set_capability(haptic->input_device, EV_FF, FF_RUMBLE);
- haptic->input_device->open = isa1200_open;
- haptic->input_device->close = isa1200_close;
- rc = input_ff_create_memless(haptic->input_device, NULL,
- isa1200_play_effect);
- if (rc < 0) {
- pr_err("unable to register with ff\n");
- goto err_free_dev;
- }
- rc = input_register_device(haptic->input_device);
- if (rc < 0) {
- pr_err("unable to register input device\n");
- goto err_ff_destroy;
- }
- return 0;
- err_ff_destroy:
- input_ff_destroy(haptic->input_device);
- err_free_dev:
- input_free_device(haptic->input_device);
- err_mem_alloc:
- kfree(haptic);
- return rc;
- }
- static int __devexit isa1200_remove(struct i2c_client *client)
- {
- struct isa1200_chip *haptic = i2c_get_clientdata(client);
- input_unregister_device(haptic->input_device);
- kfree(haptic);
- return 0;
- }
- static const struct i2c_device_id isa1200_id_table[] = {
- {"isa1200_1", 0},
- { },
- };
- MODULE_DEVICE_TABLE(i2c, isa1200_id_table);
- static const struct dev_pm_ops isa1200_pm_ops = {
- .suspend = isa1200_suspend,
- .resume = isa1200_resume,
- };
- static struct i2c_driver isa1200_driver = {
- .driver = {
- .name = "isa1200-ff-memless",
- .owner = THIS_MODULE,
- .pm = &isa1200_pm_ops,
- },
- .probe = isa1200_probe,
- .remove = __devexit_p(isa1200_remove),
- .id_table = isa1200_id_table,
- };
- static int __init isa1200_init(void)
- {
- return i2c_add_driver(&isa1200_driver);
- }
- module_init(isa1200_init);
- static void __exit isa1200_exit(void)
- {
- i2c_del_driver(&isa1200_driver);
- }
- module_exit(isa1200_exit);
- MODULE_DESCRIPTION("isa1200 based vibrator chip driver");
- MODULE_LICENSE("GPL v2");
- MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
|