Commit | Line | Data |
---|---|---|
b9a801df AS |
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 | u8 ipc_out; | |
78 | int ret; | |
79 | ||
80 | ret = intel_scu_ipc_ioread8(reg, &ipc_out); | |
81 | if (ret) | |
82 | return ret; | |
83 | ||
84 | *val = ipc_out; | |
85 | return 0; | |
86 | } | |
87 | ||
88 | static int bcove_ipc_byte_reg_write(void *context, unsigned int reg, | |
89 | unsigned int val) | |
90 | { | |
91 | u8 ipc_in = val; | |
92 | int ret; | |
93 | ||
94 | ret = intel_scu_ipc_iowrite8(reg, ipc_in); | |
95 | if (ret) | |
96 | return ret; | |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | static const struct regmap_config bcove_regmap_config = { | |
102 | .reg_bits = 16, | |
103 | .val_bits = 8, | |
104 | .max_register = 0xff, | |
105 | .reg_write = bcove_ipc_byte_reg_write, | |
106 | .reg_read = bcove_ipc_byte_reg_read, | |
107 | }; | |
108 | ||
109 | static int bcove_probe(struct platform_device *pdev) | |
110 | { | |
111 | struct device *dev = &pdev->dev; | |
112 | struct intel_soc_pmic *pmic; | |
113 | unsigned int i; | |
114 | int ret; | |
115 | ||
116 | pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); | |
117 | if (!pmic) | |
118 | return -ENOMEM; | |
119 | ||
120 | platform_set_drvdata(pdev, pmic); | |
121 | pmic->dev = &pdev->dev; | |
122 | ||
123 | pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bcove_regmap_config); | |
124 | if (IS_ERR(pmic->regmap)) | |
125 | return PTR_ERR(pmic->regmap); | |
126 | ||
127 | for (i = 0; i < ARRAY_SIZE(irq_level2_resources); i++) { | |
128 | ret = platform_get_irq(pdev, i); | |
129 | if (ret < 0) | |
130 | return ret; | |
131 | ||
132 | irq_level2_resources[i].start = ret; | |
133 | irq_level2_resources[i].end = ret; | |
134 | } | |
135 | ||
136 | return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, | |
137 | bcove_dev, ARRAY_SIZE(bcove_dev), | |
138 | NULL, 0, NULL); | |
139 | } | |
140 | ||
141 | static const struct acpi_device_id bcove_acpi_ids[] = { | |
142 | { "INTC100E" }, | |
143 | {} | |
144 | }; | |
145 | MODULE_DEVICE_TABLE(acpi, bcove_acpi_ids); | |
146 | ||
147 | static struct platform_driver bcove_driver = { | |
148 | .driver = { | |
149 | .name = "intel_soc_pmic_mrfld", | |
150 | .acpi_match_table = bcove_acpi_ids, | |
151 | }, | |
152 | .probe = bcove_probe, | |
153 | }; | |
154 | module_platform_driver(bcove_driver); | |
155 | ||
156 | MODULE_DESCRIPTION("IPC driver for Intel SoC Basin Cove PMIC"); | |
157 | MODULE_LICENSE("GPL v2"); |