intel_soc_pmic_chtwc.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC
  3. *
  4. * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
  5. *
  6. * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
  7. * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. #include <linux/acpi.h>
  14. #include <linux/delay.h>
  15. #include <linux/err.h>
  16. #include <linux/i2c.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/kernel.h>
  19. #include <linux/mfd/core.h>
  20. #include <linux/mfd/intel_soc_pmic.h>
  21. #include <linux/regmap.h>
  22. /* PMIC device registers */
  23. #define REG_OFFSET_MASK GENMASK(7, 0)
  24. #define REG_ADDR_MASK GENMASK(15, 8)
  25. #define REG_ADDR_SHIFT 8
  26. #define CHT_WC_IRQLVL1 0x6e02
  27. #define CHT_WC_IRQLVL1_MASK 0x6e0e
  28. /* Whiskey Cove PMIC share same ACPI ID between different platforms */
  29. #define CHT_WC_HRV 3
  30. /* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */
  31. enum {
  32. CHT_WC_PWRSRC_IRQ = 0,
  33. CHT_WC_THRM_IRQ,
  34. CHT_WC_BCU_IRQ,
  35. CHT_WC_ADC_IRQ,
  36. CHT_WC_EXT_CHGR_IRQ,
  37. CHT_WC_GPIO_IRQ,
  38. /* There is no irq 6 */
  39. CHT_WC_CRIT_IRQ = 7,
  40. };
  41. static struct resource cht_wc_pwrsrc_resources[] = {
  42. DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ),
  43. };
  44. static struct resource cht_wc_ext_charger_resources[] = {
  45. DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ),
  46. };
  47. static struct mfd_cell cht_wc_dev[] = {
  48. {
  49. .name = "cht_wcove_pwrsrc",
  50. .num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources),
  51. .resources = cht_wc_pwrsrc_resources,
  52. }, {
  53. .name = "cht_wcove_ext_chgr",
  54. .num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources),
  55. .resources = cht_wc_ext_charger_resources,
  56. },
  57. { .name = "cht_wcove_region", },
  58. };
  59. /*
  60. * The CHT Whiskey Cove covers multiple I2C addresses, with a 1 Byte
  61. * register address space per I2C address, so we use 16 bit register
  62. * addresses where the high 8 bits contain the I2C client address.
  63. */
  64. static int cht_wc_byte_reg_read(void *context, unsigned int reg,
  65. unsigned int *val)
  66. {
  67. struct i2c_client *client = context;
  68. int ret, orig_addr = client->addr;
  69. if (!(reg & REG_ADDR_MASK)) {
  70. dev_err(&client->dev, "Error I2C address not specified\n");
  71. return -EINVAL;
  72. }
  73. client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
  74. ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK);
  75. client->addr = orig_addr;
  76. if (ret < 0)
  77. return ret;
  78. *val = ret;
  79. return 0;
  80. }
  81. static int cht_wc_byte_reg_write(void *context, unsigned int reg,
  82. unsigned int val)
  83. {
  84. struct i2c_client *client = context;
  85. int ret, orig_addr = client->addr;
  86. if (!(reg & REG_ADDR_MASK)) {
  87. dev_err(&client->dev, "Error I2C address not specified\n");
  88. return -EINVAL;
  89. }
  90. client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
  91. ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val);
  92. client->addr = orig_addr;
  93. return ret;
  94. }
  95. static const struct regmap_config cht_wc_regmap_cfg = {
  96. .reg_bits = 16,
  97. .val_bits = 8,
  98. .reg_write = cht_wc_byte_reg_write,
  99. .reg_read = cht_wc_byte_reg_read,
  100. };
  101. static const struct regmap_irq cht_wc_regmap_irqs[] = {
  102. REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)),
  103. REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)),
  104. REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)),
  105. REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)),
  106. REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)),
  107. REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)),
  108. REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)),
  109. };
  110. static const struct regmap_irq_chip cht_wc_regmap_irq_chip = {
  111. .name = "cht_wc_irq_chip",
  112. .status_base = CHT_WC_IRQLVL1,
  113. .mask_base = CHT_WC_IRQLVL1_MASK,
  114. .irqs = cht_wc_regmap_irqs,
  115. .num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs),
  116. .num_regs = 1,
  117. };
  118. static int cht_wc_probe(struct i2c_client *client)
  119. {
  120. struct device *dev = &client->dev;
  121. struct intel_soc_pmic *pmic;
  122. acpi_status status;
  123. unsigned long long hrv;
  124. int ret;
  125. status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv);
  126. if (ACPI_FAILURE(status)) {
  127. dev_err(dev, "Failed to get PMIC hardware revision\n");
  128. return -ENODEV;
  129. }
  130. if (hrv != CHT_WC_HRV) {
  131. dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv);
  132. return -ENODEV;
  133. }
  134. if (client->irq < 0) {
  135. dev_err(dev, "Invalid IRQ\n");
  136. return -EINVAL;
  137. }
  138. pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
  139. if (!pmic)
  140. return -ENOMEM;
  141. pmic->irq = client->irq;
  142. pmic->dev = dev;
  143. i2c_set_clientdata(client, pmic);
  144. pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg);
  145. if (IS_ERR(pmic->regmap))
  146. return PTR_ERR(pmic->regmap);
  147. ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
  148. IRQF_ONESHOT | IRQF_SHARED, 0,
  149. &cht_wc_regmap_irq_chip,
  150. &pmic->irq_chip_data);
  151. if (ret)
  152. return ret;
  153. return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
  154. cht_wc_dev, ARRAY_SIZE(cht_wc_dev), NULL, 0,
  155. regmap_irq_get_domain(pmic->irq_chip_data));
  156. }
  157. static void cht_wc_shutdown(struct i2c_client *client)
  158. {
  159. struct intel_soc_pmic *pmic = i2c_get_clientdata(client);
  160. disable_irq(pmic->irq);
  161. }
  162. static int __maybe_unused cht_wc_suspend(struct device *dev)
  163. {
  164. struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
  165. disable_irq(pmic->irq);
  166. return 0;
  167. }
  168. static int __maybe_unused cht_wc_resume(struct device *dev)
  169. {
  170. struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
  171. enable_irq(pmic->irq);
  172. return 0;
  173. }
  174. static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume);
  175. static const struct i2c_device_id cht_wc_i2c_id[] = {
  176. { }
  177. };
  178. static const struct acpi_device_id cht_wc_acpi_ids[] = {
  179. { "INT34D3", },
  180. { }
  181. };
  182. static struct i2c_driver cht_wc_driver = {
  183. .driver = {
  184. .name = "CHT Whiskey Cove PMIC",
  185. .pm = &cht_wc_pm_ops,
  186. .acpi_match_table = cht_wc_acpi_ids,
  187. },
  188. .probe_new = cht_wc_probe,
  189. .shutdown = cht_wc_shutdown,
  190. .id_table = cht_wc_i2c_id,
  191. };
  192. builtin_i2c_driver(cht_wc_driver);