184c99db8SAshish Jangam /* 284c99db8SAshish Jangam * I2C access for DA9052 PMICs. 384c99db8SAshish Jangam * 484c99db8SAshish Jangam * Copyright(c) 2011 Dialog Semiconductor Ltd. 584c99db8SAshish Jangam * 684c99db8SAshish Jangam * Author: David Dajun Chen <dchen@diasemi.com> 784c99db8SAshish Jangam * 884c99db8SAshish Jangam * This program is free software; you can redistribute it and/or modify 984c99db8SAshish Jangam * it under the terms of the GNU General Public License as published by 1084c99db8SAshish Jangam * the Free Software Foundation; either version 2 of the License, or 1184c99db8SAshish Jangam * (at your option) any later version. 1284c99db8SAshish Jangam * 1384c99db8SAshish Jangam */ 1484c99db8SAshish Jangam 1584c99db8SAshish Jangam #include <linux/device.h> 1684c99db8SAshish Jangam #include <linux/module.h> 1784c99db8SAshish Jangam #include <linux/input.h> 1884c99db8SAshish Jangam #include <linux/mfd/core.h> 1984c99db8SAshish Jangam #include <linux/i2c.h> 2084c99db8SAshish Jangam #include <linux/err.h> 2184c99db8SAshish Jangam 2284c99db8SAshish Jangam #include <linux/mfd/da9052/da9052.h> 2384c99db8SAshish Jangam #include <linux/mfd/da9052/reg.h> 2484c99db8SAshish Jangam 2558d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 2658d114b6SYing-Chun Liu (PaulLiu) #include <linux/of.h> 2758d114b6SYing-Chun Liu (PaulLiu) #include <linux/of_device.h> 2858d114b6SYing-Chun Liu (PaulLiu) #endif 2958d114b6SYing-Chun Liu (PaulLiu) 3084c99db8SAshish Jangam static int da9052_i2c_enable_multiwrite(struct da9052 *da9052) 3184c99db8SAshish Jangam { 3284c99db8SAshish Jangam int reg_val, ret; 3384c99db8SAshish Jangam 3484c99db8SAshish Jangam ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, ®_val); 3584c99db8SAshish Jangam if (ret < 0) 3684c99db8SAshish Jangam return ret; 3784c99db8SAshish Jangam 3884c99db8SAshish Jangam if (reg_val & DA9052_CONTROL_B_WRITEMODE) { 3984c99db8SAshish Jangam reg_val &= ~DA9052_CONTROL_B_WRITEMODE; 4084c99db8SAshish Jangam ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG, 4184c99db8SAshish Jangam reg_val); 4284c99db8SAshish Jangam if (ret < 0) 4384c99db8SAshish Jangam return ret; 4484c99db8SAshish Jangam } 4584c99db8SAshish Jangam 4684c99db8SAshish Jangam return 0; 4784c99db8SAshish Jangam } 4884c99db8SAshish Jangam 49e27d650bSArnd Bergmann static const struct i2c_device_id da9052_i2c_id[] = { 5058d114b6SYing-Chun Liu (PaulLiu) {"da9052", DA9052}, 5158d114b6SYing-Chun Liu (PaulLiu) {"da9053-aa", DA9053_AA}, 5258d114b6SYing-Chun Liu (PaulLiu) {"da9053-ba", DA9053_BA}, 5358d114b6SYing-Chun Liu (PaulLiu) {"da9053-bb", DA9053_BB}, 5458d114b6SYing-Chun Liu (PaulLiu) {} 5558d114b6SYing-Chun Liu (PaulLiu) }; 5658d114b6SYing-Chun Liu (PaulLiu) 5758d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 5858d114b6SYing-Chun Liu (PaulLiu) static const struct of_device_id dialog_dt_ids[] = { 5958d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] }, 6058d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] }, 6158d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9053-ab", .data = &da9052_i2c_id[2] }, 6258d114b6SYing-Chun Liu (PaulLiu) { .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] }, 6358d114b6SYing-Chun Liu (PaulLiu) { /* sentinel */ } 6458d114b6SYing-Chun Liu (PaulLiu) }; 6558d114b6SYing-Chun Liu (PaulLiu) #endif 6658d114b6SYing-Chun Liu (PaulLiu) 6784c99db8SAshish Jangam static int __devinit da9052_i2c_probe(struct i2c_client *client, 6884c99db8SAshish Jangam const struct i2c_device_id *id) 6984c99db8SAshish Jangam { 7084c99db8SAshish Jangam struct da9052 *da9052; 7184c99db8SAshish Jangam int ret; 7284c99db8SAshish Jangam 736608a5e2SAxel Lin da9052 = devm_kzalloc(&client->dev, sizeof(struct da9052), GFP_KERNEL); 7484c99db8SAshish Jangam if (!da9052) 7584c99db8SAshish Jangam return -ENOMEM; 7684c99db8SAshish Jangam 7784c99db8SAshish Jangam if (!i2c_check_functionality(client->adapter, 7884c99db8SAshish Jangam I2C_FUNC_SMBUS_BYTE_DATA)) { 7984c99db8SAshish Jangam dev_info(&client->dev, "Error in %s:i2c_check_functionality\n", 8084c99db8SAshish Jangam __func__); 816608a5e2SAxel Lin return -ENODEV; 8284c99db8SAshish Jangam } 8384c99db8SAshish Jangam 8484c99db8SAshish Jangam da9052->dev = &client->dev; 8584c99db8SAshish Jangam da9052->chip_irq = client->irq; 8684c99db8SAshish Jangam 8784c99db8SAshish Jangam i2c_set_clientdata(client, da9052); 8884c99db8SAshish Jangam 896608a5e2SAxel Lin da9052->regmap = devm_regmap_init_i2c(client, &da9052_regmap_config); 9084c99db8SAshish Jangam if (IS_ERR(da9052->regmap)) { 9184c99db8SAshish Jangam ret = PTR_ERR(da9052->regmap); 9284c99db8SAshish Jangam dev_err(&client->dev, "Failed to allocate register map: %d\n", 9384c99db8SAshish Jangam ret); 946608a5e2SAxel Lin return ret; 9584c99db8SAshish Jangam } 9684c99db8SAshish Jangam 9784c99db8SAshish Jangam ret = da9052_i2c_enable_multiwrite(da9052); 9884c99db8SAshish Jangam if (ret < 0) 996608a5e2SAxel Lin return ret; 10084c99db8SAshish Jangam 10158d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 10258d114b6SYing-Chun Liu (PaulLiu) if (!id) { 10358d114b6SYing-Chun Liu (PaulLiu) struct device_node *np = client->dev.of_node; 10458d114b6SYing-Chun Liu (PaulLiu) const struct of_device_id *deviceid; 10558d114b6SYing-Chun Liu (PaulLiu) 1069e69ab41SOlof Johansson deviceid = of_match_node(dialog_dt_ids, np); 107e27d650bSArnd Bergmann id = deviceid->data; 10858d114b6SYing-Chun Liu (PaulLiu) } 10958d114b6SYing-Chun Liu (PaulLiu) #endif 11058d114b6SYing-Chun Liu (PaulLiu) 11158d114b6SYing-Chun Liu (PaulLiu) if (!id) { 11258d114b6SYing-Chun Liu (PaulLiu) ret = -ENODEV; 11358d114b6SYing-Chun Liu (PaulLiu) dev_err(&client->dev, "id is null.\n"); 1146608a5e2SAxel Lin return ret; 11558d114b6SYing-Chun Liu (PaulLiu) } 11658d114b6SYing-Chun Liu (PaulLiu) 11784c99db8SAshish Jangam ret = da9052_device_init(da9052, id->driver_data); 11884c99db8SAshish Jangam if (ret != 0) 1196608a5e2SAxel Lin return ret; 12084c99db8SAshish Jangam 12184c99db8SAshish Jangam return 0; 12284c99db8SAshish Jangam } 12384c99db8SAshish Jangam 124bcc2d6d6SDmitry Torokhov static int __devexit da9052_i2c_remove(struct i2c_client *client) 12584c99db8SAshish Jangam { 12684c99db8SAshish Jangam struct da9052 *da9052 = i2c_get_clientdata(client); 12784c99db8SAshish Jangam 12884c99db8SAshish Jangam da9052_device_exit(da9052); 12984c99db8SAshish Jangam return 0; 13084c99db8SAshish Jangam } 13184c99db8SAshish Jangam 13284c99db8SAshish Jangam static struct i2c_driver da9052_i2c_driver = { 13384c99db8SAshish Jangam .probe = da9052_i2c_probe, 134bcc2d6d6SDmitry Torokhov .remove = __devexit_p(da9052_i2c_remove), 13584c99db8SAshish Jangam .id_table = da9052_i2c_id, 13684c99db8SAshish Jangam .driver = { 13784c99db8SAshish Jangam .name = "da9052", 13884c99db8SAshish Jangam .owner = THIS_MODULE, 13958d114b6SYing-Chun Liu (PaulLiu) #ifdef CONFIG_OF 14058d114b6SYing-Chun Liu (PaulLiu) .of_match_table = dialog_dt_ids, 14158d114b6SYing-Chun Liu (PaulLiu) #endif 14284c99db8SAshish Jangam }, 14384c99db8SAshish Jangam }; 14484c99db8SAshish Jangam 14584c99db8SAshish Jangam static int __init da9052_i2c_init(void) 14684c99db8SAshish Jangam { 14784c99db8SAshish Jangam int ret; 14884c99db8SAshish Jangam 14984c99db8SAshish Jangam ret = i2c_add_driver(&da9052_i2c_driver); 15084c99db8SAshish Jangam if (ret != 0) { 15184c99db8SAshish Jangam pr_err("DA9052 I2C registration failed %d\n", ret); 15284c99db8SAshish Jangam return ret; 15384c99db8SAshish Jangam } 15484c99db8SAshish Jangam 15584c99db8SAshish Jangam return 0; 15684c99db8SAshish Jangam } 15784c99db8SAshish Jangam subsys_initcall(da9052_i2c_init); 15884c99db8SAshish Jangam 15984c99db8SAshish Jangam static void __exit da9052_i2c_exit(void) 16084c99db8SAshish Jangam { 16184c99db8SAshish Jangam i2c_del_driver(&da9052_i2c_driver); 16284c99db8SAshish Jangam } 16384c99db8SAshish Jangam module_exit(da9052_i2c_exit); 16484c99db8SAshish Jangam 16584c99db8SAshish Jangam MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 16684c99db8SAshish Jangam MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC"); 16784c99db8SAshish Jangam MODULE_LICENSE("GPL"); 168