1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Device access for Basin Cove PMIC |
4 | * |
5 | * Copyright (c) 2019, Intel Corporation. |
6 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
7 | */ |
8 | |
9 | #include <linux/acpi.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/mfd/core.h> |
12 | #include <linux/mfd/intel_soc_pmic.h> |
13 | #include <linux/mfd/intel_soc_pmic_mrfld.h> |
14 | #include <linux/module.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/regmap.h> |
17 | |
18 | #include <asm/intel_scu_ipc.h> |
19 | |
20 | /* |
21 | * Level 2 IRQs |
22 | * |
23 | * Firmware on the systems with Basin Cove PMIC services Level 1 IRQs |
24 | * without an assistance. Thus, each of the Level 1 IRQ is represented |
25 | * as a separate RTE in IOAPIC. |
26 | */ |
27 | static struct resource irq_level2_resources[] = { |
28 | DEFINE_RES_IRQ(0), /* power button */ |
29 | DEFINE_RES_IRQ(0), /* TMU */ |
30 | DEFINE_RES_IRQ(0), /* thermal */ |
31 | DEFINE_RES_IRQ(0), /* BCU */ |
32 | DEFINE_RES_IRQ(0), /* ADC */ |
33 | DEFINE_RES_IRQ(0), /* charger */ |
34 | DEFINE_RES_IRQ(0), /* GPIO */ |
35 | }; |
36 | |
37 | static const struct mfd_cell bcove_dev[] = { |
38 | { |
39 | .name = "mrfld_bcove_pwrbtn" , |
40 | .num_resources = 1, |
41 | .resources = &irq_level2_resources[0], |
42 | }, { |
43 | .name = "mrfld_bcove_tmu" , |
44 | .num_resources = 1, |
45 | .resources = &irq_level2_resources[1], |
46 | }, { |
47 | .name = "mrfld_bcove_thermal" , |
48 | .num_resources = 1, |
49 | .resources = &irq_level2_resources[2], |
50 | }, { |
51 | .name = "mrfld_bcove_bcu" , |
52 | .num_resources = 1, |
53 | .resources = &irq_level2_resources[3], |
54 | }, { |
55 | .name = "mrfld_bcove_adc" , |
56 | .num_resources = 1, |
57 | .resources = &irq_level2_resources[4], |
58 | }, { |
59 | .name = "mrfld_bcove_charger" , |
60 | .num_resources = 1, |
61 | .resources = &irq_level2_resources[5], |
62 | }, { |
63 | .name = "mrfld_bcove_pwrsrc" , |
64 | .num_resources = 1, |
65 | .resources = &irq_level2_resources[5], |
66 | }, { |
67 | .name = "mrfld_bcove_gpio" , |
68 | .num_resources = 1, |
69 | .resources = &irq_level2_resources[6], |
70 | }, |
71 | { .name = "mrfld_bcove_region" , }, |
72 | }; |
73 | |
74 | static int bcove_ipc_byte_reg_read(void *context, unsigned int reg, |
75 | unsigned int *val) |
76 | { |
77 | struct intel_soc_pmic *pmic = context; |
78 | u8 ipc_out; |
79 | int ret; |
80 | |
81 | ret = intel_scu_ipc_dev_ioread8(scu: pmic->scu, addr: reg, data: &ipc_out); |
82 | if (ret) |
83 | return ret; |
84 | |
85 | *val = ipc_out; |
86 | return 0; |
87 | } |
88 | |
89 | static int bcove_ipc_byte_reg_write(void *context, unsigned int reg, |
90 | unsigned int val) |
91 | { |
92 | struct intel_soc_pmic *pmic = context; |
93 | u8 ipc_in = val; |
94 | |
95 | return intel_scu_ipc_dev_iowrite8(scu: pmic->scu, addr: reg, data: ipc_in); |
96 | } |
97 | |
98 | static const struct regmap_config bcove_regmap_config = { |
99 | .reg_bits = 16, |
100 | .val_bits = 8, |
101 | .max_register = 0xff, |
102 | .reg_write = bcove_ipc_byte_reg_write, |
103 | .reg_read = bcove_ipc_byte_reg_read, |
104 | }; |
105 | |
106 | static int bcove_probe(struct platform_device *pdev) |
107 | { |
108 | struct device *dev = &pdev->dev; |
109 | struct intel_soc_pmic *pmic; |
110 | unsigned int i; |
111 | int ret; |
112 | |
113 | pmic = devm_kzalloc(dev, size: sizeof(*pmic), GFP_KERNEL); |
114 | if (!pmic) |
115 | return -ENOMEM; |
116 | |
117 | pmic->scu = devm_intel_scu_ipc_dev_get(dev); |
118 | if (!pmic->scu) |
119 | return -ENOMEM; |
120 | |
121 | platform_set_drvdata(pdev, data: pmic); |
122 | pmic->dev = &pdev->dev; |
123 | |
124 | pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bcove_regmap_config); |
125 | if (IS_ERR(ptr: pmic->regmap)) |
126 | return PTR_ERR(ptr: pmic->regmap); |
127 | |
128 | for (i = 0; i < ARRAY_SIZE(irq_level2_resources); i++) { |
129 | ret = platform_get_irq(pdev, i); |
130 | if (ret < 0) |
131 | return ret; |
132 | |
133 | irq_level2_resources[i].start = ret; |
134 | irq_level2_resources[i].end = ret; |
135 | } |
136 | |
137 | return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, |
138 | cells: bcove_dev, ARRAY_SIZE(bcove_dev), |
139 | NULL, irq_base: 0, NULL); |
140 | } |
141 | |
142 | static const struct acpi_device_id bcove_acpi_ids[] = { |
143 | { "INTC100E" }, |
144 | {} |
145 | }; |
146 | MODULE_DEVICE_TABLE(acpi, bcove_acpi_ids); |
147 | |
148 | static struct platform_driver bcove_driver = { |
149 | .driver = { |
150 | .name = "intel_soc_pmic_mrfld" , |
151 | .acpi_match_table = bcove_acpi_ids, |
152 | }, |
153 | .probe = bcove_probe, |
154 | }; |
155 | module_platform_driver(bcove_driver); |
156 | |
157 | MODULE_DESCRIPTION("IPC driver for Intel SoC Basin Cove PMIC" ); |
158 | MODULE_LICENSE("GPL v2" ); |
159 | |