s5m-core.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * s5m87xx.c
  3. *
  4. * Copyright (c) 2011 Samsung Electronics Co., Ltd
  5. * http://www.samsung.com
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2 of the License, or (at your
  10. * option) any later version.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/moduleparam.h>
  15. #include <linux/init.h>
  16. #include <linux/err.h>
  17. #include <linux/slab.h>
  18. #include <linux/i2c.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/pm_runtime.h>
  21. #include <linux/mutex.h>
  22. #include <linux/mfd/core.h>
  23. #include <linux/mfd/s5m87xx/s5m-core.h>
  24. #include <linux/mfd/s5m87xx/s5m-pmic.h>
  25. #include <linux/mfd/s5m87xx/s5m-rtc.h>
  26. #include <linux/regmap.h>
  27. static struct mfd_cell s5m87xx_devs[] = {
  28. {
  29. .name = "s5m8767-pmic",
  30. }, {
  31. .name = "s5m-rtc",
  32. },
  33. };
  34. int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
  35. {
  36. return regmap_read(s5m87xx->regmap, reg, dest);
  37. }
  38. EXPORT_SYMBOL_GPL(s5m_reg_read);
  39. int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
  40. {
  41. return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
  42. }
  43. EXPORT_SYMBOL_GPL(s5m_bulk_read);
  44. int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
  45. {
  46. return regmap_write(s5m87xx->regmap, reg, value);
  47. }
  48. EXPORT_SYMBOL_GPL(s5m_reg_write);
  49. int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
  50. {
  51. return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
  52. }
  53. EXPORT_SYMBOL_GPL(s5m_bulk_write);
  54. int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
  55. {
  56. return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
  57. }
  58. EXPORT_SYMBOL_GPL(s5m_reg_update);
  59. static struct regmap_config s5m_regmap_config = {
  60. .reg_bits = 8,
  61. .val_bits = 8,
  62. };
  63. static int s5m87xx_i2c_probe(struct i2c_client *i2c,
  64. const struct i2c_device_id *id)
  65. {
  66. struct s5m_platform_data *pdata = i2c->dev.platform_data;
  67. struct s5m87xx_dev *s5m87xx;
  68. int ret = 0;
  69. int error;
  70. s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
  71. if (s5m87xx == NULL)
  72. return -ENOMEM;
  73. i2c_set_clientdata(i2c, s5m87xx);
  74. s5m87xx->dev = &i2c->dev;
  75. s5m87xx->i2c = i2c;
  76. s5m87xx->irq = i2c->irq;
  77. s5m87xx->type = id->driver_data;
  78. if (pdata) {
  79. s5m87xx->device_type = pdata->device_type;
  80. s5m87xx->ono = pdata->ono;
  81. s5m87xx->irq_base = pdata->irq_base;
  82. s5m87xx->wakeup = pdata->wakeup;
  83. }
  84. s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
  85. if (IS_ERR(s5m87xx->regmap)) {
  86. error = PTR_ERR(s5m87xx->regmap);
  87. dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
  88. error);
  89. goto err;
  90. }
  91. s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
  92. i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
  93. if (pdata->cfg_pmic_irq)
  94. pdata->cfg_pmic_irq();
  95. s5m_irq_init(s5m87xx);
  96. pm_runtime_set_active(s5m87xx->dev);
  97. ret = mfd_add_devices(s5m87xx->dev, -1,
  98. s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
  99. NULL, 0);
  100. if (ret < 0)
  101. goto err;
  102. return ret;
  103. err:
  104. mfd_remove_devices(s5m87xx->dev);
  105. s5m_irq_exit(s5m87xx);
  106. i2c_unregister_device(s5m87xx->rtc);
  107. regmap_exit(s5m87xx->regmap);
  108. kfree(s5m87xx);
  109. return ret;
  110. }
  111. static int s5m87xx_i2c_remove(struct i2c_client *i2c)
  112. {
  113. struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
  114. mfd_remove_devices(s5m87xx->dev);
  115. s5m_irq_exit(s5m87xx);
  116. i2c_unregister_device(s5m87xx->rtc);
  117. regmap_exit(s5m87xx->regmap);
  118. kfree(s5m87xx);
  119. return 0;
  120. }
  121. static const struct i2c_device_id s5m87xx_i2c_id[] = {
  122. { "s5m87xx", 0 },
  123. { }
  124. };
  125. MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
  126. static struct i2c_driver s5m87xx_i2c_driver = {
  127. .driver = {
  128. .name = "s5m87xx",
  129. .owner = THIS_MODULE,
  130. },
  131. .probe = s5m87xx_i2c_probe,
  132. .remove = s5m87xx_i2c_remove,
  133. .id_table = s5m87xx_i2c_id,
  134. };
  135. static int __init s5m87xx_i2c_init(void)
  136. {
  137. return i2c_add_driver(&s5m87xx_i2c_driver);
  138. }
  139. subsys_initcall(s5m87xx_i2c_init);
  140. static void __exit s5m87xx_i2c_exit(void)
  141. {
  142. i2c_del_driver(&s5m87xx_i2c_driver);
  143. }
  144. module_exit(s5m87xx_i2c_exit);
  145. MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
  146. MODULE_DESCRIPTION("Core support for the S5M MFD");
  147. MODULE_LICENSE("GPL");