Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i3c: Add Phytium i3c controller support #144

Merged
merged 8 commits into from
May 27, 2024
4 changes: 3 additions & 1 deletion Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ allOf:

properties:
compatible:
const: cdns,i3c-master
enum:
- cdns,i3c-master
- phytium,cdns-i3c-master

reg:
maxItems: 1
Expand Down
35 changes: 35 additions & 0 deletions Documentation/devicetree/bindings/i3c/phytium,i3c-master.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause

* Phytium I3C controller

This I3C controller is for Phytium Soc.

Required properties:
- compatible: Shall be "phytium,cdns-i3c-master"
- clocks: Shall reference the pclk and sysclk
- clock-names: Shall contain "pclk" and "sysclk"
- interrupts: The interrupt line connected to this I3C master
- reg: I3C master registers
- #address-cells: Shall be set to 1
- #size-cells: Shall be set to 0
- i2c-scl-hz: I2C CLK frequency
- i3c-scl-hz: I3C CLK frequency

Example:

i3c-master@28045000 {
compatible = "phytium,cdns-i3c-master";
reg = <0x0 0x28045000 0x0 0x1000>;
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&coreclock>, <&i3csysclock>;
clock-names = "pclk", "sysclk";
#address-cells = <1>;
#size-cells = <0>;
i2c-scl-hz = <400000>;
i3c-scl-hz = <1000000>;

nunchuk: nunchuk@52 {
compatible = "nintendo,nunchuk";
reg = <0x52 0x0 0x10>;
};
};
1 change: 1 addition & 0 deletions drivers/i3c/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
i3c-y := device.o master.o
obj-$(CONFIG_I3C) += i3c.o
i3c-$(CONFIG_ACPI) += i3c_master_acpi.o
obj-$(CONFIG_I3C) += master/
95 changes: 95 additions & 0 deletions drivers/i3c/i3c_master_acpi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for I3C ACPI Interface
*
* Copyright (C) 2021-2023 Phytium Technology Co., Ltd.
*/

#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include "i3c_master_acpi.h"

static int i3c_master_acpi_parse_val(union acpi_object *store_elements, char *method,
int count, u32 *value)
{
int i, package_count, ret = -1;
union acpi_object *acpi_elements;

for (i = 0; i < count; i++) {
acpi_elements = store_elements;
if (acpi_elements[i].type == ACPI_TYPE_PACKAGE) {
package_count = acpi_elements[i].package.count;

if (package_count == 2) {
acpi_elements = acpi_elements[i].package.elements;
if (acpi_elements[0].type == ACPI_TYPE_STRING) {
if (!strcmp(acpi_elements[0].string.pointer, method)) {
*value = acpi_elements[1].integer.value;
ret = 0;
break;
}
}
}
}
}
return ret;
}

int i3c_master_acpi_get_params(acpi_handle handle, char *method, u32 *value)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
acpi_status status = 0;
union acpi_object *obj;
int count, ret = -1;

status = acpi_evaluate_object(handle, "_DSD", NULL, &buf);
if (ACPI_FAILURE(status)) {
kfree(buf.pointer);
return -2;
}

obj = (union acpi_object *)buf.pointer;

if (obj->type == ACPI_TYPE_PACKAGE) {
union acpi_object *acpi_elements;
union acpi_object *store_elements;

acpi_elements = obj->package.elements;
if ((obj->package.count >= 2) && (acpi_elements[1].type == ACPI_TYPE_PACKAGE)) {
count = acpi_elements[1].package.count;
acpi_elements = acpi_elements[1].package.elements;

store_elements = acpi_elements;
ret = i3c_master_acpi_parse_val(store_elements, method, count, value);
}
}

kfree(buf.pointer);
return ret;
}
EXPORT_SYMBOL_GPL(i3c_master_acpi_get_params);

void i3c_master_acpi_clk_params(acpi_handle handle, char *method,
u32 *pres_ctrl0, u32 *pres_ctrl1, u32 *thd_delay)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
union acpi_object *obj;

if (ACPI_FAILURE(acpi_evaluate_object(handle, method, NULL, &buf)))
return;

obj = (union acpi_object *)buf.pointer;
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) {
const union acpi_object *objs = obj->package.elements;

*pres_ctrl0 = (u32)objs[0].integer.value;
*pres_ctrl1 = (u32)objs[1].integer.value;
*thd_delay = (u32)objs[2].integer.value;
}

kfree(buf.pointer);
}
EXPORT_SYMBOL_GPL(i3c_master_acpi_clk_params);
18 changes: 18 additions & 0 deletions drivers/i3c/i3c_master_acpi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for I3C ACPI Interface
*
* Copyright (C) 2021-2023 Phytium Technology Co., Ltd.
*/

#ifndef __I3C_MASTER_ACPI_H
#define __I3C_MASTER_ACPI_H

#include <linux/acpi.h>
#include <acpi/acpi_bus.h>

int i3c_master_acpi_get_params(acpi_handle handle, char *method, u32 *value);
void i3c_master_acpi_clk_params(acpi_handle handle, char *method,
u32 *pres_ctrl0, u32 *pres_ctrl1, u32 *thd_delay);

#endif
Loading
Loading