/* * intel_mid_vibra.c - Intel vibrator driver for Clovertrail and mrfld phone * * Copyright (C) 2011-13 Intel Corp * Author: KP, Jeeja * Author: Vinod Koul * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * 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. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include "mid_vibra.h" #include #include #ifdef VIBRA_PWM union sst_pwmctrl_reg { struct { u32 pwmtd:8; u32 pwmbu:22; u32 pwmswupdate:1; u32 pwmenable:1; } part; u32 full; }; static int vibra_driver_write(struct i2c_adapter *adap, u8 i2c_addr, u8 reg, u8 value) { struct i2c_msg msg; u8 buffer[2]; int ret = 0; buffer[0] = reg; buffer[1] = value; pr_debug("write for %x, value %x", buffer[0], buffer[1]); msg.addr = i2c_addr; msg.len = 2; msg.buf = (u8 *)&buffer; msg.flags = 0; ret = i2c_transfer(adap, &msg, 1); if (ret != 1) pr_err("i2c write error: %d for reg %x", ret, reg); else ret = 0; return ret; } static int vibra_driver_read(struct i2c_adapter *adap, u8 i2c_addr, u8 reg, u8 *value) { struct i2c_msg xfer[2]; int ret = 0; xfer[0].addr = i2c_addr; xfer[0].flags = 0; xfer[0].len = 1; xfer[0].buf = (u8 *)® /* write address */ xfer[1].addr = i2c_addr; xfer[1].flags = I2C_M_RD; xfer[1].len = 1; xfer[1].buf = (u8 *)value; /*Read value */ ret = i2c_transfer(adap, xfer, 2); if (ret != 2) { pr_err("%s:i2c transfer err:%d for reg %x", __func__, ret, reg); } else { pr_debug("Read from 0x%x, the val 0x%x\n", reg, *value); return 0; } return ret; } static int vibra_soc_pwm_configure(struct vibra_info *info, bool enable) { union sst_pwmctrl_reg pwmctrl; if (enable) { lnw_gpio_set_alt(info->gpio_pwm, info->alt_fn); /*1. Enable the PWM by setting PWM enable bit to 1 */ pwmctrl.full = readl(info->shim); pr_debug("Vibra:Read pwmctrl %x\n", readl(info->shim)); pwmctrl.part.pwmenable = 1; writel(pwmctrl.full, info->shim); /*2. Read the PWM register to make sure there is no pending *update. */ pwmctrl.full = readl(info->shim); pr_debug("Read pwmctrl %x\n", pwmctrl.full); /*check pwnswupdate bit */ if (pwmctrl.part.pwmswupdate) return -EBUSY; /*Base unit == 1*/ pwmctrl.part.pwmswupdate = 0x1; /* validate values input */ if (*info->base_unit > info->max_base_unit) *info->base_unit = info->max_base_unit; if (*info->duty_cycle > info->max_duty_cycle) *info->duty_cycle = info->max_duty_cycle; pwmctrl.part.pwmbu = *info->base_unit; pwmctrl.part.pwmtd = *info->duty_cycle; writel(pwmctrl.full, info->shim); pr_debug("Read pwmctrl %x\n", pwmctrl.full); } else { /*disable PWM block */ lnw_gpio_set_alt(info->gpio_pwm, 0); /*1. setting PWM enable bit to 0 */ pwmctrl.full = readl(info->shim); pwmctrl.part.pwmenable = 0; writel(pwmctrl.full, info->shim); } return 0; } /* Enable vibra */ static void vibra_drv2605_enable(struct vibra_info *info) { pr_debug("%s: Enable", __func__); trace_vibrator(1); mutex_lock(&info->lock); pm_runtime_get_sync(info->dev); /* Enable the EN line */ gpio_set_value(info->gpio_en, 1); /* Wait for 850us per spec, give 100us buffer */ usleep_range(950, 1000); /* Enable the Trigger line */ info->pwm_configure(info, true); info->enabled = true; mutex_unlock(&info->lock); } static void vibra_disable(struct vibra_info *info) { pr_debug("%s: Disable", __func__); trace_vibrator(0); mutex_lock(&info->lock); gpio_set_value_cansleep(info->gpio_en, 0); info->enabled = false; info->pwm_configure(info, false); pm_runtime_put(info->dev); mutex_unlock(&info->lock); } static void vibra_drv8601_enable(struct vibra_info *info) { pr_debug("%s: Enable", __func__); trace_vibrator(1); mutex_lock(&info->lock); pm_runtime_get_sync(info->dev); info->pwm_configure(info, true); gpio_set_value_cansleep(info->gpio_en, 1); info->enabled = true; mutex_unlock(&info->lock); } /******************************************************************************* * SYSFS * ******************************************************************************/ static ssize_t vibra_show_vibrator(struct device *dev, struct device_attribute *attr, char *buf) { struct vibra_info *info = dev_get_drvdata(dev); return sprintf(buf, "%d\n", info->enabled); } static ssize_t vibra_set_vibrator(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { long vibrator_enable; struct vibra_info *info = dev_get_drvdata(dev); if (kstrtol(buf, 0, &vibrator_enable)) return -EINVAL; if (vibrator_enable == info->enabled) return len; else if (vibrator_enable == 0) info->disable(info); else if (vibrator_enable != 0) info->enable(info); else return -EINVAL; return len; } unsigned long mid_vibra_base_unit; unsigned long mid_vibra_duty_cycle; static DEVICE_ATTR(vibrator, S_IRUGO | S_IWUSR, vibra_show_vibrator, vibra_set_vibrator); static DEVICE_ULONG_ATTR(pwm_baseunit, S_IRUGO | S_IWUSR, mid_vibra_base_unit); static DEVICE_ULONG_ATTR(pwm_ontime_div, S_IRUGO | S_IWUSR, mid_vibra_duty_cycle); static struct attribute *vibra_attrs[] = { &dev_attr_vibrator.attr, &dev_attr_pwm_baseunit.attr.attr, &dev_attr_pwm_ontime_div.attr.attr, 0, }; static const struct attribute_group vibra_attr_group = { .attrs = vibra_attrs, }; /*** Module ***/ #if CONFIG_PM static int intel_vibra_runtime_suspend(struct device *dev) { struct vibra_info *info = dev_get_drvdata(dev); pr_debug("In %s\n", __func__); info->pwm_configure(info, false); return 0; } static int intel_vibra_runtime_resume(struct device *dev) { pr_debug("In %s\n", __func__); return 0; } static void intel_vibra_complete(struct device *dev) { pr_debug("In %s\n", __func__); intel_vibra_runtime_resume(dev); } static const struct dev_pm_ops intel_mid_vibra_pm_ops = { .prepare = intel_vibra_runtime_suspend, .complete = intel_vibra_complete, .runtime_suspend = intel_vibra_runtime_suspend, .runtime_resume = intel_vibra_runtime_resume, }; #endif #define MRFLD_VIBRA_BUS 0x2 /* vibra_drv2604_calibrate: initializes the ext drv and auto calibrates it one time * * @info: vibra driver context */ static int vibra_drv2605_calibrate(struct vibra_info *info) { #define DRV2605_I2C_ADDR 0x5a #define DRV2605_STATUS 0x00 #define DRV2605_MODE 0x01 #define DRV2605_GO 0x0c #define DRV2605_VOLTAGE 0x16 #define DRV2605_CLAMP 0x17 #define DRV2605_AUTO_CAL_COMP 0x18 #define DRV2605_FB_CONTROL 0x1a #define DRV2605_AUTO_CALIB 0x07 #define DRV2605_2_0V 0x5b #define DRV2605_LRA 0xa4 #define DRV2605_PWM 0x03 #define DRV2605_GO_BIT 0x01 #define DRV2605_STANDBY_BIT 6 #define DRV2605_DIAG_RESULT_BIT 3 /* default value of the register 0x18 */ #define DRV2605_AUTO_CAL_COMP_VALUE 0x0D struct i2c_adapter *adap; u8 status = 0, mode = 0; u8 reg_val = DRV2605_AUTO_CAL_COMP_VALUE; adap = i2c_get_adapter(MRFLD_VIBRA_BUS); if (!adap) { pr_err("can't find bus adapter"); return -EIO; } /* enable gpio first */ gpio_set_value(info->gpio_en, 1); /* wait for gpio to settle and drv to accept i2c */ usleep_range(1000, 1100); /* get the device out of standby */ vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_MODE, DRV2605_PWM); vibra_driver_read(adap, DRV2605_I2C_ADDR, DRV2605_MODE, &mode); /* Is Device Ready?? */ if (!((mode >> DRV2605_STANDBY_BIT) & 0x1)) { vibra_driver_read(adap, DRV2605_I2C_ADDR, DRV2605_STATUS, &status); vibra_driver_read(adap, DRV2605_I2C_ADDR, DRV2605_AUTO_CAL_COMP, ®_val); /* Is it Auto Calibrated?? */ /* Check the diag result bit & default value of auto calib comp register */ if (!((status >> DRV2605_DIAG_RESULT_BIT) & 0x1) && (reg_val != DRV2605_AUTO_CAL_COMP_VALUE)) { if (!((INTEL_MID_BOARD(1, PHONE, MOFD)) || (INTEL_MID_BOARD(1, TABLET, MOFD)))) { gpio_set_value(info->gpio_en, 0); pr_debug("Do Nothing - Device Calibrated\n"); return 0; } } } pr_warn("Calibrating the vibra..\n"); /*put device in auto calibrate mode*/ vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_MODE, DRV2605_AUTO_CALIB); vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_FB_CONTROL, DRV2605_LRA); vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_VOLTAGE, DRV2605_2_0V); vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_CLAMP, DRV2605_2_0V); vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_GO, DRV2605_GO_BIT); /* wait for auto calibration to complete * polling of driver does not work */ msleep(1000); /* set the driver in pwm mode */ vibra_driver_write(adap, DRV2605_I2C_ADDR, DRV2605_MODE, DRV2605_PWM); gpio_set_value(info->gpio_en, 0); return 0; } struct vibra_info *mid_vibra_setup(struct device *dev, struct mid_vibra_pdata *data) { struct vibra_info *info; pr_debug("probe data divisor %x, base %x, alt_fn %d ext_drv %d, name: %s", data->time_divisor, data->base_unit, data->alt_fn, data->ext_drv, data->name); info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) { pr_err("%s: no memory for driver context", __func__); return NULL; } info->alt_fn = data->alt_fn; info->ext_drv = data->ext_drv; info->gpio_en = data->gpio_en; info->gpio_pwm = data->gpio_pwm; info->name = data->name; info->dev = dev; mutex_init(&info->lock); info->vibra_attr_group = &vibra_attr_group; mid_vibra_base_unit = data->base_unit; mid_vibra_duty_cycle = data->time_divisor; info->base_unit = &mid_vibra_base_unit; info->duty_cycle = &mid_vibra_duty_cycle; /* ops */ if (!strncmp(info->name, "drv8601", 8)) { info->enable = vibra_drv8601_enable; } else if (!strncmp(info->name, "drv2605", 8)) { info->enable = vibra_drv2605_enable; } else if (!strncmp(info->name, "drv2603", 8)) { info->enable = vibra_drv2605_enable; } else { pr_err("%s: unsupported vibrator device", __func__); return NULL; } info->disable = vibra_disable; return info; } static int intel_mid_vibra_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct vibra_info *info; struct device *dev = &pci->dev; struct mid_vibra_pdata *data; int ret; pr_debug("Probe for DID %x\n", pci->device); data = pci->dev.platform_data; if (!data) { dev_err(&pci->dev, "Failed to get vibrator platform data\n"); return -ENODEV; } info = mid_vibra_setup(dev, data); if (!info) return -ENODEV; info->pwm_configure = vibra_soc_pwm_configure; info->max_base_unit = INTEL_VIBRA_MAX_BASEUNIT; info->max_duty_cycle = INTEL_VIBRA_MAX_TIMEDIVISOR; pr_debug("using gpios en: %d, pwm %d", info->gpio_en, info->gpio_pwm); ret = gpio_request_one(info->gpio_en, GPIOF_DIR_OUT, "VIBRA ENABLE"); if (ret != 0) { pr_err("gpio_request(%d) fails:%d\n", info->gpio_en, ret); goto out; } /* Init the device */ ret = pci_enable_device(pci); if (ret) { pr_err("device can't be enabled\n"); goto do_freegpio_vibra_enable; } ret = pci_request_regions(pci, INTEL_VIBRA_DRV_NAME); if (ret) goto do_disable_device; pci_dev_get(pci); /* vibra Shim */ info->shim = pci_ioremap_bar(pci, 0); if (!info->shim) { pr_err("ioremap failed for vibra driver\n"); goto do_release_regions; } pr_debug("Base reg: %#x", (unsigned int) pci_resource_start(pci, 0)); ret = sysfs_create_group(&dev->kobj, info->vibra_attr_group); if (ret) { pr_err("could not register sysfs files\n"); goto do_unmap_shim; } if (info->ext_drv) vibra_drv2605_calibrate(info); pci_set_drvdata(pci, info); pm_runtime_allow(&pci->dev); pm_runtime_put_noidle(&pci->dev); return ret; do_unmap_shim: iounmap(info->shim); do_release_regions: pci_release_regions(pci); do_disable_device: pci_disable_device(pci); do_freegpio_vibra_enable: gpio_free(info->gpio_en); out: return ret; } static void intel_mid_vibra_remove(struct pci_dev *pci) { struct vibra_info *info = pci_get_drvdata(pci); gpio_free(info->gpio_en); sysfs_remove_group(&info->dev->kobj, info->vibra_attr_group); iounmap(info->shim); pci_release_regions(pci); pci_disable_device(pci); pci_set_drvdata(pci, NULL); } /* PCI Routines */ static DEFINE_PCI_DEVICE_TABLE(intel_vibra_ids) = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VIBRA_CLV), 0}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VIBRA_MRFLD), 0}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VIBRA_MOOR), 0}, { 0, } }; MODULE_DEVICE_TABLE(pci, intel_vibra_ids); static struct pci_driver vibra_driver = { .name = INTEL_VIBRA_DRV_NAME, .id_table = intel_vibra_ids, .probe = intel_mid_vibra_probe, .remove = intel_mid_vibra_remove, #ifdef CONFIG_PM .driver = { .pm = &intel_mid_vibra_pm_ops, }, #endif }; static const struct acpi_device_id vibra_acpi_ids[]; void *mid_vibra_acpi_get_drvdata(const char *hid) { const struct acpi_device_id *id; for (id = vibra_acpi_ids; id->id[0]; id++) if (!strncmp(id->id, hid, 16)) return (void *)id->driver_data; return 0; } static const struct acpi_device_id vibra_acpi_ids[] = { { "VIB8601", (kernel_ulong_t) &pmic_vibra_data_byt_ffrd8 }, {}, }; MODULE_DEVICE_TABLE(acpi, vibra_acpi_ids); static struct platform_driver plat_vibra_driver = { .driver = { .name = "intel_mid_pmic_vibra", .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(vibra_acpi_ids), #ifdef CONFIG_PM .pm = &intel_mid_vibra_pm_ops, #endif }, .probe = intel_mid_plat_vibra_probe, .remove = intel_mid_plat_vibra_remove, }; #else #define REGADDR_PMIC_VSYS_SX_EN 0x63 #define VIBRA_STATE_ON 0x03 #define VIBRA_STATE_OFF 0x02 #define VIBRA_STATE_ENABLE 0x01 static struct class *vibradir_class; #endif static void vibra_pmic_direct_enable(struct dev_direct_vibrator *vdev) { pr_debug("%s:\n", __func__); if (NULL == vdev) return; trace_vibrator(1); mutex_lock(&vdev->vibra_lock); if(VIBRA_STATE_ENABLE == vdev->vibradir_state) { pr_debug("%s: enable\n", __func__); intel_mid_pmic_writeb((u32)REGADDR_PMIC_VSYS_SX_EN, (u32)VIBRA_STATE_ON); } else { pr_debug("%s: disable\n", __func__); intel_mid_pmic_writeb((u32)REGADDR_PMIC_VSYS_SX_EN, (u32)VIBRA_STATE_OFF); } mutex_unlock(&vdev->vibra_lock); } static struct dev_direct_vibrator vibradir_dev = { .name = "vibrator", }; static ssize_t vibra_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_direct_vibrator *vdev = dev_get_drvdata(dev); if (NULL == vdev) return -EINVAL; return sprintf(buf, "%d\n", vdev->vibradir_state); } static ssize_t vibra_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct dev_direct_vibrator *vdev = dev_get_drvdata(dev); int value; if (NULL == vdev) return size; sscanf(buf, "%d", &value); if(value != 0) value = 1; vdev->vibradir_state = value; pr_debug("vibra update, state:%d\n", vdev->vibradir_state); vdev->enable(vdev); return size; } static DEVICE_ATTR(vibrator, S_IRUGO | S_IWUSR, vibra_show, vibra_store); static ssize_t ontime_div_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_direct_vibrator *vdev = dev_get_drvdata(dev); if (NULL == vdev) return -EINVAL; return sprintf(buf, "%d\n", vdev->vibradir_ontime_div); } static ssize_t ontime_div_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct dev_direct_vibrator *vdev = dev_get_drvdata(dev); int value; if (NULL == vdev) return size; sscanf(buf, "%d", &value); vdev->vibradir_ontime_div = value; pr_debug("ontime_div_store: %d\n", value); return size; } static DEVICE_ATTR(pwm_ontime_div, S_IRUGO | S_IWUSR, ontime_div_show, ontime_div_store); static ssize_t baseunit_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dev_direct_vibrator *vdev = dev_get_drvdata(dev); if (NULL == vdev) return -EINVAL; return sprintf(buf, "%d\n", vdev->vibradir_baseunit); } static ssize_t baseunit_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct dev_direct_vibrator *vdev = dev_get_drvdata(dev); int value; if (NULL == vdev) return size; sscanf(buf, "%d", &value); vdev->vibradir_baseunit = value; pr_debug("vibradir_baseunit: %d\n", value); return size; } static DEVICE_ATTR(pwm_baseunit, S_IRUGO | S_IWUSR, baseunit_show, baseunit_store); void vibradir_dev_setup(struct dev_direct_vibrator *vdev) { if (NULL == vdev) return; vdev->vibradir_state = 0; vdev->vibradir_ontime_div = 0; vdev->vibradir_baseunit = 0; mutex_init(&vdev->vibra_lock); vdev->enable = vibra_pmic_direct_enable; } int vibradir_dev_register(struct dev_direct_vibrator *vdev) { int ret = 0; pr_debug("%s\n", __func__); if (!vdev || !vdev->name) return -EINVAL; vdev->dev = device_create(vibradir_class, NULL, MKDEV(0, vdev->index), NULL, vdev->name); if (IS_ERR(vdev->dev)) return PTR_ERR(vdev->dev); ret = device_create_file(vdev->dev, &dev_attr_vibrator); if (ret < 0) goto err_create_file; ret = device_create_file(vdev->dev, &dev_attr_pwm_ontime_div); if (ret < 0) goto err_create_file; ret = device_create_file(vdev->dev, &dev_attr_pwm_baseunit); if (ret < 0) goto err_create_file; dev_set_drvdata(vdev->dev, vdev); return ret; err_create_file: device_destroy(vibradir_class, MKDEV(0, vdev->index)); pr_debug(KERN_ERR "vibradirect: Failed to register driver %s\n", vdev->name); return ret; } EXPORT_SYMBOL_GPL(vibradir_dev_register); void vibradir_dev_unregister(struct dev_direct_vibrator *vdev) { device_remove_file(vdev->dev, &dev_attr_vibrator); device_destroy(vibradir_class, MKDEV(0, vdev->index)); dev_set_drvdata(vdev->dev, NULL); } EXPORT_SYMBOL_GPL(vibradir_dev_unregister); /** * intel_mid_vibra_init - Module init function * * Registers with PCI * Registers platform * Init all data strutures */ static int __init intel_mid_vibra_init(void) { int ret = 0; #ifdef VIBRA_PWM /* Register with PCI */ ret = pci_register_driver(&vibra_driver); if (ret) pr_err("PCI register failed\n"); ret = platform_driver_register(&plat_vibra_driver); if (ret) pr_err("Platform register failed\n"); #else intel_mid_pmic_writeb((u32)REGADDR_PMIC_VSYS_SX_EN, (u32)VIBRA_STATE_OFF); vibradir_class = class_create(THIS_MODULE, "pmicvibradirect"); if (IS_ERR(vibradir_class)) pr_debug("vibra failed to create class\n"); else { vibradir_dev_register(&vibradir_dev); vibradir_dev_setup(&vibradir_dev); } #endif return ret; } /** * intel_mid_vibra_exit - Module exit function * * Unregisters with PCI * Unregisters platform * Frees all data strutures */ static void __exit intel_mid_vibra_exit(void) { #ifdef VIBRA_PWM pci_unregister_driver(&vibra_driver); platform_driver_unregister(&plat_vibra_driver); #else vibradir_dev_unregister(&vibradir_dev); class_destroy(vibradir_class); #endif pr_debug("intel_mid_vibra driver exited\n"); return; } late_initcall(intel_mid_vibra_init); module_exit(intel_mid_vibra_exit); MODULE_ALIAS("pci:intel_mid_vibra"); MODULE_DESCRIPTION("Intel(R) MID Vibra driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("KP Jeeja ");