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 | { | |
50362083 | 77 | struct intel_soc_pmic *pmic = context; |
b9a801df AS |
78 | u8 ipc_out; |
79 | int ret; | |
80 | ||
50362083 | 81 | ret = intel_scu_ipc_dev_ioread8(pmic->scu, reg, &ipc_out); |
b9a801df AS |
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 | { | |
50362083 | 92 | struct intel_soc_pmic *pmic = context; |
b9a801df | 93 | u8 ipc_in = val; |
b9a801df | 94 | |
4ee1d9dc | 95 | return intel_scu_ipc_dev_iowrite8(pmic->scu, reg, ipc_in); |
b9a801df AS |
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, sizeof(*pmic), GFP_KERNEL); | |
114 | if (!pmic) | |
115 | return -ENOMEM; | |
116 | ||
50362083 MW |
117 | pmic->scu = devm_intel_scu_ipc_dev_get(dev); |
118 | if (!pmic->scu) | |
119 | return -ENOMEM; | |
120 | ||
b9a801df AS |
121 | platform_set_drvdata(pdev, pmic); |
122 | pmic->dev = &pdev->dev; | |
123 | ||
124 | pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bcove_regmap_config); | |
125 | if (IS_ERR(pmic->regmap)) | |
126 | return PTR_ERR(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 | bcove_dev, ARRAY_SIZE(bcove_dev), | |
139 | NULL, 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"); |