1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for Intel MSIC
5 * Copyright (C) 2011, Intel Corporation
6 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
10 #include <linux/gpio.h>
12 #include <linux/init.h>
13 #include <linux/mfd/core.h>
14 #include <linux/mfd/intel_msic.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
18 #include <asm/intel_scu_ipc.h>
20 #define MSIC_VENDOR(id) ((id >> 6) & 3)
21 #define MSIC_VERSION(id) (id & 0x3f)
22 #define MSIC_MAJOR(id) ('A' + ((id >> 3) & 7))
23 #define MSIC_MINOR(id) (id & 7)
26 * MSIC interrupt tree is readable from SRAM at INTEL_MSIC_IRQ_PHYS_BASE.
27 * Since IRQ block starts from address 0x002 we need to subtract that from
28 * the actual IRQ status register address.
30 #define MSIC_IRQ_STATUS(x) (INTEL_MSIC_IRQ_PHYS_BASE + ((x) - 2))
31 #define MSIC_IRQ_STATUS_ACCDET MSIC_IRQ_STATUS(INTEL_MSIC_ACCDET)
34 * The SCU hardware has limitation of 16 bytes per read/write buffer on
37 #define SCU_IPC_RWBUF_LIMIT 16
40 * struct intel_msic - an MSIC MFD instance
41 * @pdev: pointer to the platform device
43 * @version: chip version
44 * @irq_base: base address of the mapped MSIC SRAM interrupt tree
47 struct platform_device
*pdev
;
50 void __iomem
*irq_base
;
53 static struct resource msic_touch_resources
[] = {
57 static struct resource msic_adc_resources
[] = {
61 static struct resource msic_battery_resources
[] = {
65 static struct resource msic_gpio_resources
[] = {
69 static struct resource msic_audio_resources
[] = {
70 DEFINE_RES_IRQ_NAMED(0, "IRQ"),
72 * We will pass IRQ_BASE to the driver now but this can be removed
73 * when/if the driver starts to use intel_msic_irq_read().
75 DEFINE_RES_MEM_NAMED(MSIC_IRQ_STATUS_ACCDET
, 1, "IRQ_BASE"),
78 static struct resource msic_hdmi_resources
[] = {
82 static struct resource msic_thermal_resources
[] = {
86 static struct resource msic_power_btn_resources
[] = {
90 static struct resource msic_ocd_resources
[] = {
95 * Devices that are part of the MSIC and are available via firmware
96 * populated SFI DEVS table.
98 static struct mfd_cell msic_devs
[] = {
99 [INTEL_MSIC_BLOCK_TOUCH
] = {
100 .name
= "msic_touch",
101 .num_resources
= ARRAY_SIZE(msic_touch_resources
),
102 .resources
= msic_touch_resources
,
104 [INTEL_MSIC_BLOCK_ADC
] = {
106 .num_resources
= ARRAY_SIZE(msic_adc_resources
),
107 .resources
= msic_adc_resources
,
109 [INTEL_MSIC_BLOCK_BATTERY
] = {
110 .name
= "msic_battery",
111 .num_resources
= ARRAY_SIZE(msic_battery_resources
),
112 .resources
= msic_battery_resources
,
114 [INTEL_MSIC_BLOCK_GPIO
] = {
116 .num_resources
= ARRAY_SIZE(msic_gpio_resources
),
117 .resources
= msic_gpio_resources
,
119 [INTEL_MSIC_BLOCK_AUDIO
] = {
120 .name
= "msic_audio",
121 .num_resources
= ARRAY_SIZE(msic_audio_resources
),
122 .resources
= msic_audio_resources
,
124 [INTEL_MSIC_BLOCK_HDMI
] = {
126 .num_resources
= ARRAY_SIZE(msic_hdmi_resources
),
127 .resources
= msic_hdmi_resources
,
129 [INTEL_MSIC_BLOCK_THERMAL
] = {
130 .name
= "msic_thermal",
131 .num_resources
= ARRAY_SIZE(msic_thermal_resources
),
132 .resources
= msic_thermal_resources
,
134 [INTEL_MSIC_BLOCK_POWER_BTN
] = {
135 .name
= "msic_power_btn",
136 .num_resources
= ARRAY_SIZE(msic_power_btn_resources
),
137 .resources
= msic_power_btn_resources
,
139 [INTEL_MSIC_BLOCK_OCD
] = {
141 .num_resources
= ARRAY_SIZE(msic_ocd_resources
),
142 .resources
= msic_ocd_resources
,
147 * Other MSIC related devices which are not directly available via SFI DEVS
148 * table. These can be pseudo devices, regulators etc. which are needed for
149 * different purposes.
151 * These devices appear only after the MSIC driver itself is initialized so
152 * we can guarantee that the SCU IPC interface is ready.
154 static const struct mfd_cell msic_other_devs
[] = {
155 /* Audio codec in the MSIC */
163 * intel_msic_reg_read - read a single MSIC register
164 * @reg: register to read
165 * @val: register value is placed here
167 * Read a single register from MSIC. Returns %0 on success and negative
168 * errno in case of failure.
170 * Function may sleep.
172 int intel_msic_reg_read(unsigned short reg
, u8
*val
)
174 return intel_scu_ipc_ioread8(reg
, val
);
176 EXPORT_SYMBOL_GPL(intel_msic_reg_read
);
179 * intel_msic_reg_write - write a single MSIC register
180 * @reg: register to write
181 * @val: value to write to that register
183 * Write a single MSIC register. Returns 0 on success and negative
184 * errno in case of failure.
186 * Function may sleep.
188 int intel_msic_reg_write(unsigned short reg
, u8 val
)
190 return intel_scu_ipc_iowrite8(reg
, val
);
192 EXPORT_SYMBOL_GPL(intel_msic_reg_write
);
195 * intel_msic_reg_update - update a single MSIC register
196 * @reg: register to update
197 * @val: value to write to the register
198 * @mask: specifies which of the bits are updated (%0 = don't update,
201 * Perform an update to a register @reg. @mask is used to specify which
202 * bits are updated. Returns %0 in case of success and negative errno in
205 * Function may sleep.
207 int intel_msic_reg_update(unsigned short reg
, u8 val
, u8 mask
)
209 return intel_scu_ipc_update_register(reg
, val
, mask
);
211 EXPORT_SYMBOL_GPL(intel_msic_reg_update
);
214 * intel_msic_bulk_read - read an array of registers
215 * @reg: array of register addresses to read
216 * @buf: array where the read values are placed
217 * @count: number of registers to read
219 * Function reads @count registers from the MSIC using addresses passed in
220 * @reg. Read values are placed in @buf. Reads are performed atomically
223 * Returns %0 in case of success and negative errno in case of failure.
225 * Function may sleep.
227 int intel_msic_bulk_read(unsigned short *reg
, u8
*buf
, size_t count
)
229 if (WARN_ON(count
> SCU_IPC_RWBUF_LIMIT
))
232 return intel_scu_ipc_readv(reg
, buf
, count
);
234 EXPORT_SYMBOL_GPL(intel_msic_bulk_read
);
237 * intel_msic_bulk_write - write an array of values to the MSIC registers
238 * @reg: array of registers to write
239 * @buf: values to write to each register
240 * @count: number of registers to write
242 * Function writes @count registers in @buf to MSIC. Writes are performed
243 * atomically wrt MSIC. Returns %0 in case of success and negative errno in
246 * Function may sleep.
248 int intel_msic_bulk_write(unsigned short *reg
, u8
*buf
, size_t count
)
250 if (WARN_ON(count
> SCU_IPC_RWBUF_LIMIT
))
253 return intel_scu_ipc_writev(reg
, buf
, count
);
255 EXPORT_SYMBOL_GPL(intel_msic_bulk_write
);
258 * intel_msic_irq_read - read a register from an MSIC interrupt tree
259 * @msic: MSIC instance
260 * @reg: interrupt register (between %INTEL_MSIC_IRQLVL1 and
261 * %INTEL_MSIC_RESETIRQ2)
262 * @val: value of the register is placed here
264 * This function can be used by an MSIC subdevice interrupt handler to read
265 * a register value from the MSIC interrupt tree. In this way subdevice
266 * drivers don't have to map in the interrupt tree themselves but can just
267 * call this function instead.
269 * Function doesn't sleep and is callable from interrupt context.
271 * Returns %-EINVAL if @reg is outside of the allowed register region.
273 int intel_msic_irq_read(struct intel_msic
*msic
, unsigned short reg
, u8
*val
)
275 if (WARN_ON(reg
< INTEL_MSIC_IRQLVL1
|| reg
> INTEL_MSIC_RESETIRQ2
))
278 *val
= readb(msic
->irq_base
+ (reg
- INTEL_MSIC_IRQLVL1
));
281 EXPORT_SYMBOL_GPL(intel_msic_irq_read
);
283 static int intel_msic_init_devices(struct intel_msic
*msic
)
285 struct platform_device
*pdev
= msic
->pdev
;
286 struct intel_msic_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
290 struct mfd_cell
*cell
= &msic_devs
[INTEL_MSIC_BLOCK_GPIO
];
292 cell
->platform_data
= pdata
->gpio
;
293 cell
->pdata_size
= sizeof(*pdata
->gpio
);
297 unsigned gpio
= pdata
->ocd
->gpio
;
299 ret
= devm_gpio_request_one(&pdev
->dev
, gpio
,
300 GPIOF_IN
, "ocd_gpio");
302 dev_err(&pdev
->dev
, "failed to register OCD GPIO\n");
306 ret
= gpio_to_irq(gpio
);
308 dev_err(&pdev
->dev
, "no IRQ number for OCD GPIO\n");
312 /* Update the IRQ number for the OCD */
313 pdata
->irq
[INTEL_MSIC_BLOCK_OCD
] = ret
;
316 for (i
= 0; i
< ARRAY_SIZE(msic_devs
); i
++) {
320 ret
= mfd_add_devices(&pdev
->dev
, -1, &msic_devs
[i
], 1, NULL
,
321 pdata
->irq
[i
], NULL
);
326 ret
= mfd_add_devices(&pdev
->dev
, 0, msic_other_devs
,
327 ARRAY_SIZE(msic_other_devs
), NULL
, 0, NULL
);
334 mfd_remove_devices(&pdev
->dev
);
339 static void intel_msic_remove_devices(struct intel_msic
*msic
)
341 struct platform_device
*pdev
= msic
->pdev
;
343 mfd_remove_devices(&pdev
->dev
);
346 static int intel_msic_probe(struct platform_device
*pdev
)
348 struct intel_msic_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
349 struct intel_msic
*msic
;
350 struct resource
*res
;
355 dev_err(&pdev
->dev
, "no platform data passed\n");
359 /* First validate that we have an MSIC in place */
360 ret
= intel_scu_ipc_ioread8(INTEL_MSIC_ID0
, &id0
);
362 dev_err(&pdev
->dev
, "failed to identify the MSIC chip (ID0)\n");
366 ret
= intel_scu_ipc_ioread8(INTEL_MSIC_ID1
, &id1
);
368 dev_err(&pdev
->dev
, "failed to identify the MSIC chip (ID1)\n");
372 if (MSIC_VENDOR(id0
) != MSIC_VENDOR(id1
)) {
373 dev_err(&pdev
->dev
, "invalid vendor ID: %x, %x\n", id0
, id1
);
377 msic
= devm_kzalloc(&pdev
->dev
, sizeof(*msic
), GFP_KERNEL
);
381 msic
->vendor
= MSIC_VENDOR(id0
);
382 msic
->version
= MSIC_VERSION(id0
);
386 * Map in the MSIC interrupt tree area in SRAM. This is exposed to
387 * the clients via intel_msic_irq_read().
389 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
390 msic
->irq_base
= devm_ioremap_resource(&pdev
->dev
, res
);
391 if (IS_ERR(msic
->irq_base
))
392 return PTR_ERR(msic
->irq_base
);
394 platform_set_drvdata(pdev
, msic
);
396 ret
= intel_msic_init_devices(msic
);
398 dev_err(&pdev
->dev
, "failed to initialize MSIC devices\n");
402 dev_info(&pdev
->dev
, "Intel MSIC version %c%d (vendor %#x)\n",
403 MSIC_MAJOR(msic
->version
), MSIC_MINOR(msic
->version
),
409 static int intel_msic_remove(struct platform_device
*pdev
)
411 struct intel_msic
*msic
= platform_get_drvdata(pdev
);
413 intel_msic_remove_devices(msic
);
418 static struct platform_driver intel_msic_driver
= {
419 .probe
= intel_msic_probe
,
420 .remove
= intel_msic_remove
,
422 .name
= "intel_msic",
425 builtin_platform_driver(intel_msic_driver
);