* [PATCH v3 13/17] ASoC: simple-card-utils: adjust for graph on asoc_simple_card_parse_card_name
From: Kuninori Morimoto @ 2016-11-11 1:22 UTC (permalink / raw)
To: Rob Herring, Mark Brown
Cc: Linux-ALSA, Liam Girdwood, Simon, Laurent, Guennadi, Grant Likely,
Frank Rowand, Linux-DT, Linux-Kernel
In-Reply-To: <87vavurf4y.wl%kuninori.morimoto.gx@renesas.com>
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
It is assuming that the card related information is located on
"card" node, but graph case doesn't have it.
This patch adds node parameter to adjust for graph support
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- no change
include/sound/simple_card_utils.h | 1 +
sound/soc/generic/simple-card-utils.c | 3 ++-
sound/soc/generic/simple-card.c | 2 +-
sound/soc/generic/simple-scu-card.c | 2 +-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 7006150..afca6bd 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -36,6 +36,7 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
struct snd_soc_dai_link *dai_link,
const char *fmt, ...);
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
+ struct device_node *node,
char *prefix);
#define asoc_simple_card_parse_clk_cpu(node, dai_link, simple_dai) \
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 85120f5..604f1f9 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -81,6 +81,7 @@ int asoc_simple_card_set_dailink_name(struct device *dev,
EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
+ struct device_node *node,
char *prefix)
{
char prop[128];
@@ -89,7 +90,7 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%sname", prefix);
/* Parse the card name from DT */
- ret = snd_soc_of_parse_card_name(card, prop);
+ ret = snd_soc_of_parse_card_name_from_node(card, node, prop);
if (ret < 0)
return ret;
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f608f8d2..342ff53 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -401,7 +401,7 @@ static int asoc_simple_card_parse_of(struct device_node *node,
goto card_parse_end;
}
- ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
+ ret = asoc_simple_card_parse_card_name(&priv->snd_card, NULL, PREFIX);
if (ret < 0)
goto card_parse_end;
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index 348e9a7..a8164a2 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -239,7 +239,7 @@ static int asoc_simple_card_parse_of(struct device_node *node,
i++;
}
- ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX);
+ ret = asoc_simple_card_parse_card_name(&priv->snd_card, NULL, PREFIX);
if (ret < 0)
return ret;
--
1.9.1
^ permalink raw reply related
* [PATCH v3 14/17] ASoC: add simple-graph-card document
From: Kuninori Morimoto @ 2016-11-11 1:23 UTC (permalink / raw)
To: Rob Herring, Mark Brown
Cc: Linux-ALSA, Liam Girdwood, Simon, Laurent, Guennadi, Grant Likely,
Frank Rowand, Linux-DT, Linux-Kernel
In-Reply-To: <87vavurf4y.wl%kuninori.morimoto.gx@renesas.com>
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- Added how to use Simple-Graph-Card, and cleanup
.../bindings/sound/simple-graph-card.txt | 65 ++++++++++++++++++++++
1 file changed, 65 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/simple-graph-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-graph-card.txt b/Documentation/devicetree/bindings/sound/simple-graph-card.txt
new file mode 100644
index 0000000..11823b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/simple-graph-card.txt
@@ -0,0 +1,65 @@
+Simple-Graph-Card:
+
+Simple-Graph-Card specifies audio DAI connections of SoC <-> codec.
+It is based on common bindings for device graphs.
+see ${LINUX}/Documentation/devicetree/bindings/graph.txt
+
+Basically, Simple-Graph-Card property is same as Simple-Card.
+see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
+
+Below are same as Simple-Card.
+
+- simple-audio-card,name
+- simple-audio-card,widgets
+- simple-audio-card,routing
+- simple-audio-card,mclk-fs
+- simple-audio-card,hp-det-gpio
+- simple-audio-card,mic-det-gpio
+- simple-audio-card,format
+- simple-audio-card,frame-master
+- simple-audio-card,bitclock-master
+- simple-audio-card,bitclock-inversion
+- simple-audio-card,frame-inversion
+- simple-audio-card,mclk-fs
+- simple-audio-card,dai-tdm-slot-num
+- simple-audio-card,dai-tdm-slot-width
+- clocks / system-clock-frequency
+
+In Simple-Graph-Card, above properties need in CPU side port on DT.
+And it needs to have "compatible" property too.
+In addition, CPU side driver needs to call asoc_simple_card_try_to_probe_graph_card().
+It will probe specified Card driver if it could find "compatible" property on port.
+Otherwise, it will do nothing.
+
+Required properties:
+
+- compatible : "asoc-simple-graph-card";
+
+Example
+
+ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ ...
+ port {
+ ak4643_port: endpoint {
+ remote-endpoint = <&rcar_ak4643_port>;
+ clocks = <&audio_clock>;
+ };
+ };
+};
+
+rcar_sound {
+ ...
+ port {
+ compatible = "asoc-simple-graph-card";
+
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&ak4643_port>;
+ simple-audio-card,frame-master = <&ak4643_port>;
+
+ rcar_ak4643_port: endpoint {
+ remote-endpoint = <&ak4643_port>;
+ ...
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v3 15/17] ASoC: add simple-graph-card support
From: Kuninori Morimoto @ 2016-11-11 1:24 UTC (permalink / raw)
To: Rob Herring, Mark Brown
Cc: Linux-ALSA, Liam Girdwood, Simon, Laurent, Guennadi, Grant Likely,
Frank Rowand, Linux-DT, Linux-Kernel
In-Reply-To: <87vavurf4y.wl%kuninori.morimoto.gx@renesas.com>
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
graph base DT binding are used on V4L2, and ALSA SoC is using different
style of DT. In case of simple case, ALSA SoC supports simple-card
driver.
In the future, V4L2 / ALSA will support HDMI, and then, DT bindings
between V4L2 / ALSA should be merged somehow.
This patch adds graph base DT binding with simple-card style
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- no change
sound/soc/generic/Kconfig | 7 +
sound/soc/generic/Makefile | 2 +
sound/soc/generic/simple-graph-card.c | 462 ++++++++++++++++++++++++++++++++++
3 files changed, 471 insertions(+)
create mode 100644 sound/soc/generic/simple-graph-card.c
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index d023959..efefabd 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -14,3 +14,10 @@ config SND_SIMPLE_SCU_CARD
help
This option enables generic simple SCU sound card support.
It supports DPCM of multi CPU single Codec system.
+
+config SND_SIMPLE_GRAPH_CARD
+ tristate "ASoC Simple Graph sound card support"
+ depends on OF
+ select SND_SIMPLE_CARD_UTILS
+ help
+ This option enables generic simple Graph sound card support
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
index ee750f3..94eb6f1 100644
--- a/sound/soc/generic/Makefile
+++ b/sound/soc/generic/Makefile
@@ -1,7 +1,9 @@
snd-soc-simple-card-utils-objs := simple-card-utils.o
snd-soc-simple-card-objs := simple-card.o
snd-soc-simple-scu-card-objs := simple-scu-card.o
+snd-soc-simple-graph-card-objs := simple-graph-card.o
obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o
obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o
obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o
+obj-$(CONFIG_SND_SIMPLE_GRAPH_CARD) += snd-soc-simple-graph-card.o
diff --git a/sound/soc/generic/simple-graph-card.c b/sound/soc/generic/simple-graph-card.c
new file mode 100644
index 0000000..a98b13f
--- /dev/null
+++ b/sound/soc/generic/simple-graph-card.c
@@ -0,0 +1,462 @@
+/*
+ * ASoC simple graph sound card support
+ *
+ * Copyright (C) 2016 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on ${LINUX}/sound/soc/generic/simple-card.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/jack.h>
+#include <sound/simple_card_utils.h>
+
+struct asoc_simple_jack {
+ struct snd_soc_jack jack;
+ struct snd_soc_jack_pin pin;
+ struct snd_soc_jack_gpio gpio;
+};
+
+struct simple_card_data {
+ struct snd_soc_card snd_card;
+ struct simple_dai_props {
+ struct asoc_simple_dai cpu_dai;
+ struct asoc_simple_dai codec_dai;
+ unsigned int mclk_fs;
+ } *dai_props;
+ struct asoc_simple_jack hp_jack;
+ struct asoc_simple_jack mic_jack;
+ struct snd_soc_dai_link *dai_link;
+ unsigned int mclk_fs;
+};
+
+#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
+
+#define PREFIX "simple-audio-card,"
+
+#define asoc_simple_card_init_hp(card, node, sjack, prefix) \
+ asoc_simple_card_init_jack(card, node, sjack, 1, prefix)
+#define asoc_simple_card_init_mic(card, node, sjack, prefix) \
+ asoc_simple_card_init_jack(card, node, sjack, 0, prefix)
+static int asoc_simple_card_init_jack(struct snd_soc_card *card,
+ struct device_node *node,
+ struct asoc_simple_jack *sjack,
+ int is_hp, char *prefix)
+{
+ enum of_gpio_flags flags;
+ char prop[128];
+ char *pin_name;
+ char *gpio_name;
+ int mask;
+ int det;
+
+ sjack->gpio.gpio = -ENOENT;
+
+ if (is_hp) {
+ snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
+ pin_name = "Headphones";
+ gpio_name = "Headphone detection";
+ mask = SND_JACK_HEADPHONE;
+ } else {
+ snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
+ pin_name = "Mic Jack";
+ gpio_name = "Mic detection";
+ mask = SND_JACK_MICROPHONE;
+ }
+
+ det = of_get_named_gpio_flags(node, prop, 0, &flags);
+ if (det == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (gpio_is_valid(det)) {
+ sjack->pin.pin = pin_name;
+ sjack->pin.mask = mask;
+
+ sjack->gpio.name = gpio_name;
+ sjack->gpio.report = mask;
+ sjack->gpio.gpio = det;
+ sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
+ sjack->gpio.debounce_time = 150;
+
+ snd_soc_card_jack_new(card, pin_name, mask,
+ &sjack->jack,
+ &sjack->pin, 1);
+
+ snd_soc_jack_add_gpios(&sjack->jack, 1,
+ &sjack->gpio);
+ }
+
+ return 0;
+}
+
+static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack)
+{
+ if (gpio_is_valid(sjack->gpio.gpio))
+ snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio);
+}
+
+static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props =
+ simple_priv_to_props(priv, rtd->num);
+ int ret;
+
+ ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(dai_props->codec_dai.clk);
+ if (ret)
+ clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+ return ret;
+}
+
+static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props =
+ simple_priv_to_props(priv, rtd->num);
+
+ clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+ clk_disable_unprepare(dai_props->codec_dai.clk);
+}
+
+static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct simple_dai_props *dai_props =
+ simple_priv_to_props(priv, rtd->num);
+ unsigned int mclk, mclk_fs = 0;
+ int ret = 0;
+
+ if (priv->mclk_fs)
+ mclk_fs = priv->mclk_fs;
+ else if (dai_props->mclk_fs)
+ mclk_fs = dai_props->mclk_fs;
+
+ if (mclk_fs) {
+ mclk = params_rate(params) * mclk_fs;
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ goto err;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret && ret != -ENOTSUPP)
+ goto err;
+ }
+ return 0;
+err:
+ return ret;
+}
+
+static struct snd_soc_ops asoc_simple_card_ops = {
+ .startup = asoc_simple_card_startup,
+ .shutdown = asoc_simple_card_shutdown,
+ .hw_params = asoc_simple_card_hw_params,
+};
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device *cpu_dev = dev->parent;
+ struct snd_soc_dai *codec = rtd->codec_dai;
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ struct simple_dai_props *dai_props =
+ simple_priv_to_props(priv, rtd->num);
+ struct device_node *cpu_port = of_graph_get_top_port(cpu_dev);
+ int ret;
+
+ ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_init_hp(card, cpu_port, &priv->hp_jack, PREFIX);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_init_mic(card, cpu_port, &priv->hp_jack, PREFIX);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *cpu_ep,
+ struct simple_card_data *priv,
+ int idx)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+ struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
+ struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
+ struct device_node *cpu_port;
+ struct device_node *cpu_remote_ep;
+ struct device_node *codec_ep;
+ int ret;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ cpu_remote_ep = of_graph_get_remote_endpoint(codec_ep);
+
+ if (cpu_ep != cpu_remote_ep) {
+ dev_err(dev, "endpoint parse error\n");
+ ret = -EINVAL;
+ goto dai_link_of_err;
+ }
+
+ cpu_port = cpu_ep->parent;
+
+ ret = asoc_simple_card_parse_daifmt(dev, cpu_port, codec_ep,
+ PREFIX, &dai_link->dai_fmt);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs);
+
+ ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = snd_soc_of_parse_tdm_slot(cpu_ep,
+ &cpu_dai->tx_slot_mask,
+ &cpu_dai->rx_slot_mask,
+ &cpu_dai->slots,
+ &cpu_dai->slot_width);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = snd_soc_of_parse_tdm_slot(codec_ep,
+ &codec_dai->tx_slot_mask,
+ &codec_dai->rx_slot_mask,
+ &codec_dai->slots,
+ &codec_dai->slot_width);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = asoc_simple_card_parse_clk_cpu(cpu_ep, dai_link, cpu_dai);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = asoc_simple_card_parse_clk_codec(codec_ep, dai_link, codec_dai);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "%s-%s",
+ dai_link->cpu_dai_name,
+ dai_link->codec_dai_name);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ dai_link->ops = &asoc_simple_card_ops;
+ dai_link->init = asoc_simple_card_dai_init;
+
+ dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
+ dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
+ dev_dbg(dev, "\tcpu : %s / %d\n",
+ dai_link->cpu_dai_name,
+ dai_props->cpu_dai.sysclk);
+ dev_dbg(dev, "\tcodec : %s / %d\n",
+ dai_link->codec_dai_name,
+ dai_props->codec_dai.sysclk);
+
+ asoc_simple_card_canonicalize_cpu(dai_link,
+ priv->snd_card.num_links == 1);
+
+dai_link_of_err:
+ of_node_put(codec_ep);
+ of_node_put(cpu_remote_ep);
+
+ return ret;
+}
+
+static int asoc_simple_card_parse_of(struct device_node *node,
+ struct simple_card_data *priv)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device *cpu_dev = dev->parent;
+ struct device_node *top_port = of_graph_get_top_port(cpu_dev);
+ struct snd_soc_card *card = &priv->snd_card;
+ struct device_node *port, *ep;
+ int i = 0, ret;
+
+ if (!node)
+ return -EINVAL;
+
+ for_each_of_port(node, port) {
+ /* The off-codec widgets */
+ if (of_property_read_bool(port, PREFIX "widgets")) {
+ ret = snd_soc_of_parse_audio_simple_widgets_from_node(
+ &priv->snd_card,
+ port, PREFIX "widgets");
+ if (ret)
+ return ret;
+ }
+
+ /* DAPM routes */
+ if (of_property_read_bool(port, PREFIX "routing")) {
+ ret = snd_soc_of_parse_audio_routing_from_node(
+ &priv->snd_card,
+ port, PREFIX "routing");
+ if (ret)
+ return ret;
+ }
+
+ /* Factor to mclk, used in hw_params() */
+ of_property_read_u32(port, PREFIX "mclk-fs", &priv->mclk_fs);
+
+ for_each_of_endpoint_in_port(port, ep) {
+ ret = asoc_simple_card_dai_link_of(ep, priv, i);
+ if (ret < 0) {
+ of_node_put(ep);
+ return ret;
+ }
+ i++;
+ }
+ }
+
+ ret = asoc_simple_card_parse_card_name(card, top_port, PREFIX);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+ struct simple_card_data *priv;
+ struct snd_soc_dai_link *dai_link;
+ struct simple_dai_props *dai_props;
+ struct device *dev = &pdev->dev;
+ struct device *cpu_dev = pdev->dev.parent;
+ struct device_node *cpu_node = cpu_dev->of_node;
+ struct asoc_simple_graph_card_info *info = pdev->dev.platform_data;
+ int num, ret;
+
+ if (!info)
+ return -EINVAL;
+
+ /* Allocate the private data and the DAI link array */
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ num = info->endpoint_num;
+
+ dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
+ dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
+ if (!dai_props || !dai_link)
+ return -ENOMEM;
+
+ priv->dai_props = dai_props;
+ priv->dai_link = dai_link;
+
+ /* Init snd_soc_card */
+ priv->snd_card.owner = THIS_MODULE;
+ priv->snd_card.dev = dev;
+ priv->snd_card.dai_link = priv->dai_link;
+ priv->snd_card.num_links = num;
+
+ ret = asoc_simple_card_parse_of(cpu_node, priv);
+ if (ret < 0) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "parse error %d\n", ret);
+ goto err;
+ }
+
+ /*
+ * FIXME
+ *
+ * This driver is assuming that it will be called from
+ * asoc_simple_card_try_to_probe_graph_card() which
+ * is using platform_device_register_full().
+ * This means it is not came from DT. But this driver itself
+ * will be used as part of ALSA SoC (= sound card).
+ * Because of these background, it might fail in
+ * snd_pcm_lib_malloc_pages() on .hw_params.
+ * Because, noone cares its dma_ops, and result of get_dma_ops()
+ * is based on its architecture.
+ * So, it should call arch_setup_dma_ops() from somewhere,
+ * otherwise, for example, ARM is no problem, but ARM64 will be fail.
+ * But, of_platform_device_xxx() are not good solution today.
+ * This driver calls it by itself here. Please fixme
+ * see also
+ * linux/sound/soc/generic/simple-card-utils.c ::
+ * asoc_simple_card_try_to_probe_graph_card()
+ */
+ of_dma_configure(dev, dev->of_node);
+
+ snd_soc_card_set_drvdata(&priv->snd_card, priv);
+
+ ret = devm_snd_soc_register_card(dev, &priv->snd_card);
+ if (ret >= 0)
+ return ret;
+err:
+ asoc_simple_card_clean_reference(&priv->snd_card);
+
+ return ret;
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+
+ asoc_simple_card_remove_jack(&priv->hp_jack);
+ asoc_simple_card_remove_jack(&priv->mic_jack);
+
+ return asoc_simple_card_clean_reference(&priv->snd_card);
+}
+
+static struct platform_driver asoc_simple_card = {
+ .driver = {
+ .name = "asoc-simple-graph-card",
+ },
+ .probe = asoc_simple_card_probe,
+ .remove = asoc_simple_card_remove,
+};
+module_platform_driver(asoc_simple_card);
+
+MODULE_ALIAS("platform:asoc-simple-graph-card");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Simple Graph Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
--
1.9.1
^ permalink raw reply related
* [PATCH v3 16/17] ASoC: add simple-graph-scu-card document
From: Kuninori Morimoto @ 2016-11-11 1:24 UTC (permalink / raw)
To: Rob Herring, Mark Brown
Cc: Linux-ALSA, Liam Girdwood, Simon, Laurent, Guennadi, Grant Likely,
Frank Rowand, Linux-DT, Linux-Kernel
In-Reply-To: <87vavurf4y.wl%kuninori.morimoto.gx@renesas.com>
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- Added how to use Simple-Graph-SCU-Card, and cleaned-up
.../bindings/sound/simple-graph-scu-card.txt | 65 ++++++++++++++++++++++
1 file changed, 65 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/simple-graph-scu-card.txt
diff --git a/Documentation/devicetree/bindings/sound/simple-graph-scu-card.txt b/Documentation/devicetree/bindings/sound/simple-graph-scu-card.txt
new file mode 100644
index 0000000..223096a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/simple-graph-scu-card.txt
@@ -0,0 +1,65 @@
+Simple-Graph-SCU-Card:
+
+Simple-Graph-SCU-Card specifies audio DAI connections of SoC <-> codec.
+It is based on common bindings for device graphs.
+see ${LINUX}/Documentation/devicetree/bindings/graph.txt
+
+Basically, Simple-Graph-SCU-Card property is same as Simple-Card / Simple-Graph-Card.
+see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
+ ${LINUX}/Documentation/devicetree/bindings/sound/simple-graph-card.txt
+
+Main difference between Simple-Graph-Card and Simple-Graph-SCU-Card is that
+Simple-Graph-SCU-Card can use multi CPU.
+
+Required properties:
+
+- compatible : "asoc-simple-graph-scu-card";
+- simple-audio-card,routing : see simple-card.txt
+
+Example
+
+ak4643: codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ ...
+ port {
+ ak4643_fe: endpoint@0 {
+ remote-endpoint = <&rsnd_fe>;
+ ...
+ };
+ ak4643_be: endpoint@1 {
+ remote-endpoint = <&rsnd_be>;
+ ...
+ };
+ };
+};
+
+rcar_sound {
+ ...
+ ports {
+ compatible = "asoc-simple-graph-scu-card";
+
+ simple-audio-card,name = "graph-sound";
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&rsnd_fe>;
+ simple-audio-card,frame-master = <&rsnd_fe>;
+ simple-audio-card,convert-rate = <48000>;
+ simple-audio-card,convert-channels = <2>;
+ simple-audio-card,prefix = "ak4642";
+ simple-audio-card,routing =
+ "ak4642 Playback", "DAI0 Playback",
+ "ak4642 Playback", "DAI1 Playback";
+
+ port@0 {
+ rsnd_fe: endpoint@0 {
+ remote-endpoint = <&ak4643_fe>;
+ ...
+ };
+ };
+ port@1 {
+ rsnd_be: endpoint@1 {
+ remote-endpoint = <&ak4643_be>;
+ ...
+ };
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v3 17/17] ASoC: add simple-graph-scu-card support
From: Kuninori Morimoto @ 2016-11-11 1:25 UTC (permalink / raw)
To: Rob Herring, Mark Brown
Cc: Linux-ALSA, Liam Girdwood, Simon, Laurent, Guennadi, Grant Likely,
Frank Rowand, Linux-DT, Linux-Kernel
In-Reply-To: <87vavurf4y.wl%kuninori.morimoto.gx@renesas.com>
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
graph base DT binding are used on V4L2, and ALSA SoC is using different
style of DT. In case of simple case, ALSA SoC supports simple-card
driver.
In the future, V4L2 / ALSA will support HDMI, and then, DT bindings
between V4L2 / ALSA should be merged somehow.
Sometimes, we would like to use DPCM base simple-card on graph base DT.
This patch adds graph base DT binding of simple-scu-card
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3
- no change
sound/soc/generic/Kconfig | 8 +
sound/soc/generic/Makefile | 2 +
sound/soc/generic/simple-graph-scu-card.c | 417 ++++++++++++++++++++++++++++++
3 files changed, 427 insertions(+)
create mode 100644 sound/soc/generic/simple-graph-scu-card.c
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index efefabd..fc11828 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -21,3 +21,11 @@ config SND_SIMPLE_GRAPH_CARD
select SND_SIMPLE_CARD_UTILS
help
This option enables generic simple Graph sound card support
+
+config SND_SIMPLE_GRAPH_SCU_CARD
+ tristate "ASoC Simple Graph SCU sound card support"
+ depends on OF
+ select SND_SIMPLE_CARD_UTILS
+ help
+ This option enables generic simple Graph SCU sound card support.
+ It supports DPCM of multi CPU single Codec ststem.
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
index 94eb6f1..fd75b55 100644
--- a/sound/soc/generic/Makefile
+++ b/sound/soc/generic/Makefile
@@ -2,8 +2,10 @@ snd-soc-simple-card-utils-objs := simple-card-utils.o
snd-soc-simple-card-objs := simple-card.o
snd-soc-simple-scu-card-objs := simple-scu-card.o
snd-soc-simple-graph-card-objs := simple-graph-card.o
+snd-soc-simple-graph-scu-card-objs := simple-graph-scu-card.o
obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o
obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o
obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o
obj-$(CONFIG_SND_SIMPLE_GRAPH_CARD) += snd-soc-simple-graph-card.o
+obj-$(CONFIG_SND_SIMPLE_GRAPH_SCU_CARD) += snd-soc-simple-graph-scu-card.o
diff --git a/sound/soc/generic/simple-graph-scu-card.c b/sound/soc/generic/simple-graph-scu-card.c
new file mode 100644
index 0000000..39a5019
--- /dev/null
+++ b/sound/soc/generic/simple-graph-scu-card.c
@@ -0,0 +1,417 @@
+/*
+ * ASoC simple graph SCU sound card support
+ *
+ * Copyright (C) 2016 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on
+ * ${LINUX}/sound/soc/generic/simple-graph-card.c
+ * ${LINUX}/sound/soc/generic/simple-scu-card.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/jack.h>
+#include <sound/simple_card_utils.h>
+
+struct simple_card_data {
+ struct snd_soc_card snd_card;
+ struct snd_soc_codec_conf codec_conf;
+ struct asoc_simple_dai *dai_props;
+ struct snd_soc_dai_link *dai_link;
+ u32 convert_rate;
+ u32 convert_channels;
+};
+
+#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
+
+#define PREFIX "simple-audio-card,"
+
+static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct asoc_simple_dai *dai_props =
+ simple_priv_to_props(priv, rtd->num);
+
+ return clk_prepare_enable(dai_props->clk);
+}
+
+static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct asoc_simple_dai *dai_props =
+ simple_priv_to_props(priv, rtd->num);
+
+ clk_disable_unprepare(dai_props->clk);
+}
+
+static struct snd_soc_ops asoc_simple_card_ops = {
+ .startup = asoc_simple_card_startup,
+ .shutdown = asoc_simple_card_shutdown,
+};
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai;
+ struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dai_props;
+ int num = rtd->num;
+
+ dai_link = simple_priv_to_link(priv, num);
+ dai_props = simple_priv_to_props(priv, num);
+ dai = dai_link->dynamic ?
+ rtd->cpu_dai :
+ rtd->codec_dai;
+
+ return asoc_simple_card_init_dai(dai, dai_props);
+}
+
+static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (priv->convert_rate)
+ rate->min =
+ rate->max = priv->convert_rate;
+
+ if (priv->convert_channels)
+ channels->min =
+ channels->max = priv->convert_channels;
+
+ return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *port,
+ struct device_node *ep,
+ struct simple_card_data *priv,
+ unsigned int daifmt,
+ int idx, int is_fe)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
+ struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx);
+ int ret;
+
+ if (is_fe) {
+ /* BE is dummy */
+ dai_link->codec_of_node = NULL;
+ dai_link->codec_dai_name = "snd-soc-dummy-dai";
+ dai_link->codec_name = "snd-soc-dummy";
+
+ /* FE settings */
+ dai_link->dynamic = 1;
+ dai_link->dpcm_merged_format = 1;
+
+ ret = asoc_simple_card_parse_graph_cpu(ep, dai_link);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_cpu(ep, dai_link, dai_props);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "fe.%s",
+ dai_link->cpu_dai_name);
+ if (ret < 0)
+ return ret;
+
+ /* snd_card.num_links includes Codec */
+ asoc_simple_card_canonicalize_cpu(dai_link,
+ (priv->snd_card.num_links -1) == 1);
+ } else {
+ /* FE is dummy */
+ dai_link->cpu_of_node = NULL;
+ dai_link->cpu_dai_name = "snd-soc-dummy-dai";
+ dai_link->cpu_name = "snd-soc-dummy";
+
+ /* BE settings */
+ dai_link->no_pcm = 1;
+ dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup;
+
+ ret = asoc_simple_card_parse_graph_codec(ep, dai_link);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_parse_clk_codec(ep, dai_link, dai_props);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+ "be.%s",
+ dai_link->codec_dai_name);
+ if (ret < 0)
+ return ret;
+
+ snd_soc_of_parse_audio_prefix_from_node(&priv->snd_card,
+ port,
+ &priv->codec_conf,
+ dai_link->codec_of_node,
+ PREFIX "prefix");
+ }
+
+ ret = snd_soc_of_parse_tdm_slot(ep,
+ &dai_props->tx_slot_mask,
+ &dai_props->rx_slot_mask,
+ &dai_props->slots,
+ &dai_props->slot_width);
+ if (ret)
+ return ret;
+
+ ret = asoc_simple_card_canonicalize_dailink(dai_link);
+ if (ret < 0)
+ return ret;
+
+ dai_link->dai_fmt = daifmt;
+ dai_link->dpcm_playback = 1;
+ dai_link->dpcm_capture = 1;
+ dai_link->ops = &asoc_simple_card_ops;
+ dai_link->init = asoc_simple_card_dai_init;
+
+ dev_dbg(dev, "\t%s / %04x / %d\n",
+ dai_link->name,
+ dai_link->dai_fmt,
+ dai_props->sysclk);
+
+ return 0;
+}
+
+static int asoc_simple_card_parse_of(struct device_node *node,
+ struct simple_card_data *priv)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device *cpu_dev = dev->parent;
+ struct device_node *ports = of_graph_get_top_port(cpu_dev);
+ struct snd_soc_card *card = &priv->snd_card;
+ struct device_node *port, *cpu_ep, *r_cpu_ep, *codec_ep;
+ unsigned int daifmt = 0;
+ int i, ret, done;
+
+ if (!node)
+ return -EINVAL;
+
+ ret = snd_soc_of_parse_audio_routing_from_node(&priv->snd_card,
+ ports, PREFIX "routing");
+ if (ret)
+ return ret;
+
+ /* sampling rate convert */
+ of_property_read_u32(ports, PREFIX "convert-rate",
+ &priv->convert_rate);
+
+ /* channels transfer */
+ of_property_read_u32(ports, PREFIX "convert-channels",
+ &priv->convert_channels);
+
+ /*
+ * it supports multi CPU, single CODEC only here.
+ */
+
+ /* find 1st codec */
+ done = 0;
+ for_each_of_port(node, port) {
+ /* keep for_each for of_node_get/of_node_put */
+ if (done)
+ continue;
+
+ for_each_of_endpoint_in_port(port, cpu_ep) {
+ /* keep for_each for of_node_get/of_node_put */
+ if (done)
+ continue;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ r_cpu_ep = of_graph_get_remote_endpoint(codec_ep);
+ of_node_put(codec_ep);
+ of_node_put(r_cpu_ep);
+ if (cpu_ep != r_cpu_ep) {
+ ret = -EINVAL;
+ goto parse_of_err;
+ }
+
+ ret = asoc_simple_card_parse_daifmt(dev,
+ ports, codec_ep,
+ PREFIX, &daifmt);
+ if (ret < 0)
+ goto parse_of_err;
+
+ done = 1;
+ }
+ }
+
+ /* Front-End (= CPU) */
+ i = 0;
+ for_each_of_port(node, port) {
+ for_each_of_endpoint_in_port(port, cpu_ep) {
+ ret = asoc_simple_card_dai_link_of(
+ port, cpu_ep, priv, daifmt, i, 1);
+ if (ret < 0)
+ goto parse_of_err;
+ i++;
+ }
+ }
+
+ /* Back-End (= Codec) */
+ done = 0;
+ for_each_of_port(node, port) {
+ /* keep for_each for of_node_get/of_node_put */
+ if (done)
+ continue;
+
+ for_each_of_endpoint_in_port(port, cpu_ep) {
+ /* keep for_each for of_node_get/of_node_put */
+ if (done)
+ continue;
+
+ codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+ r_cpu_ep = of_graph_get_remote_endpoint(codec_ep);
+ of_node_put(codec_ep);
+ of_node_put(r_cpu_ep);
+ if (cpu_ep != r_cpu_ep) {
+ ret = -EINVAL;
+ goto parse_of_err;
+ }
+
+ ret = asoc_simple_card_dai_link_of(
+ port, codec_ep, priv, daifmt, i, 0);
+ if (ret < 0)
+ goto parse_of_err;
+ i++;
+
+ done = 1;
+ }
+ }
+
+ ret = asoc_simple_card_parse_card_name(card, ports, PREFIX);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "New card: %s\n",
+ priv->snd_card.name ? priv->snd_card.name : "");
+ dev_dbg(dev, "convert_rate %d\n", priv->convert_rate);
+ dev_dbg(dev, "convert_channels %d\n", priv->convert_channels);
+
+ return 0;
+parse_of_err:
+ of_node_put(port);
+ of_node_put(cpu_ep);
+
+ return ret;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+ struct simple_card_data *priv;
+ struct snd_soc_dai_link *dai_link;
+ struct asoc_simple_dai *dai_props;
+ struct device *dev = &pdev->dev;
+ struct device *cpu_dev = pdev->dev.parent;
+ struct device_node *cpu_node = cpu_dev->of_node;
+ struct asoc_simple_graph_card_info *info = pdev->dev.platform_data;
+ int num, ret;
+
+ /* Allocate the private data and the DAI link array */
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ /* it supports multi CPU, single CODEC only here */
+ num = info->endpoint_num + 1; /* +1 for Codec */
+
+ dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
+ dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL);
+ if (!dai_props || !dai_link)
+ return -ENOMEM;
+
+ priv->dai_props = dai_props;
+ priv->dai_link = dai_link;
+
+ /* Init snd_soc_card */
+ priv->snd_card.owner = THIS_MODULE;
+ priv->snd_card.dev = dev;
+ priv->snd_card.dai_link = priv->dai_link;
+ priv->snd_card.num_links = num;
+ priv->snd_card.codec_conf = &priv->codec_conf;
+ priv->snd_card.num_configs = 1;
+
+ ret = asoc_simple_card_parse_of(cpu_node, priv);
+ if (ret < 0) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "parse error %d\n", ret);
+ goto err;
+ }
+
+ /*
+ * FIXME
+ *
+ * This driver is assuming that it will be called from
+ * asoc_simple_card_try_to_probe_graph_card() which
+ * is using platform_device_register_full().
+ * This means it is not came from DT. But this driver itself
+ * will be used as part of ALSA SoC (= sound card).
+ * Because of these background, it might fail in
+ * snd_pcm_lib_malloc_pages() on .hw_params.
+ * Because, noone cares its dma_ops, and result of get_dma_ops()
+ * is based on its architecture.
+ * So, it should call arch_setup_dma_ops() from somewhere,
+ * otherwise, for example, ARM is no problem, but ARM64 will be fail.
+ * But, of_platform_device_xxx() are not good solution today.
+ * This driver calls it by itself here. Please fixme
+ * see also
+ * linux/sound/soc/generic/simple-card-utils.c ::
+ * asoc_simple_card_try_to_probe_graph_card()
+ */
+ of_dma_configure(dev, dev->of_node);
+
+ snd_soc_card_set_drvdata(&priv->snd_card, priv);
+
+ ret = devm_snd_soc_register_card(dev, &priv->snd_card);
+ if (ret >= 0)
+ return ret;
+err:
+ asoc_simple_card_clean_reference(&priv->snd_card);
+
+ return ret;
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+
+ return asoc_simple_card_clean_reference(&priv->snd_card);
+}
+
+static struct platform_driver asoc_simple_card = {
+ .driver = {
+ .name = "asoc-simple-graph-scu-card",
+ },
+ .probe = asoc_simple_card_probe,
+ .remove = asoc_simple_card_remove,
+};
+module_platform_driver(asoc_simple_card);
+
+MODULE_ALIAS("platform:asoc-simple-graph-scu-card");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Simple Graph SCU Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v9 2/8] power: add power sequence library
From: Peter Chen @ 2016-11-11 1:53 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Peter Chen, Greg Kroah-Hartman, Alan Stern, Ulf Hansson,
Mark Brown, Sebastian Reichel, Rob Herring, Shawn Guo,
Rafael J. Wysocki, Dmitry Eremin-Solenikov, Heiko Stuebner,
linux-arm-kernel@lists.infradead.org, p.zabel,
devicetree@vger.kernel.org, Pawel Moll, Mark Rutland,
open list:ULTRA-WIDEBAND (UWB) SUBSYSTEM:, Arnd Bergmann
In-Reply-To: <CAJZ5v0ioqMqoaJqK0CTXafWRKoohmZSiOWKRgVZ9DR3_8+-YDw@mail.gmail.com>
On Fri, Nov 11, 2016 at 02:05:01AM +0100, Rafael J. Wysocki wrote:
> On Tue, Nov 8, 2016 at 3:51 AM, Peter Chen <peter.chen@nxp.com> wrote:
> > We have an well-known problem that the device needs to do some power
> > sequence before it can be recognized by related host, the typical
> > example like hard-wired mmc devices and usb devices.
> >
> > This power sequence is hard to be described at device tree and handled by
> > related host driver, so we have created a common power sequence
> > library to cover this requirement. The core code has supplied
> > some common helpers for host driver, and individual power sequence
> > libraries handle kinds of power sequence for devices. The pwrseq
> > librares always need to allocate extra instance for compatible
> > string match.
> >
> > pwrseq_generic is intended for general purpose of power sequence, which
> > handles gpios and clocks currently, and can cover other controls in
> > future. The host driver just needs to call of_pwrseq_on/of_pwrseq_off
> > if only one power sequence is needed, else call of_pwrseq_on_list
> > /of_pwrseq_off_list instead (eg, USB hub driver).
> >
> > For new power sequence library, it can add its compatible string
> > to pwrseq_of_match_table, then the pwrseq core will match it with
> > DT's, and choose this library at runtime.
>
> In the first place, please document this stuff better than you have so
> far. To a minimum, add kerneldoc comments to all new non-trivial new
> functions to document what they are for and how they are expected to
> be used (especially the ones exported to drivers).
>
Thanks for your comments.
I will add kerneldoc for main APIs.
> Also, is there any guidance available for people who may want to use it?
No doc now, only some guidance in this commit log.
> > +config PWRSEQ_GENERIC
> > + bool "Generic power sequence control"
> > + depends on OF
> > + select POWER_SEQUENCE
> > + help
> > + It is used for drivers which needs to do power sequence
> > + (eg, turn on clock, toggle reset gpio) before the related
> > + devices can be found by hardware. This generic one can be
> > + used for common power sequence control.
>
> I wouldn't set it up this way.
>
> There are two problems here.
>
> First, say a distro is going to ship a multiplatform generic kernel.
> How they are going to figure out whether or not to set the new symbol
> in that kernel?
>
> Second, how users are supposed to know whether or not they will need
> it even if they build the kernel by themselves?
>
> It would be better IMO to set things up to select the new symbol from
> places making use of the code depending on it.
>
Will change it like below:
#
# Power Sequence library
#
menuconfig POWER_SEQUENCE
bool "Power sequence control"
depends on OF
help
It is used for drivers which needs to do power sequence
(eg, turn on clock, toggle reset gpio) before the related
devices can be found by hardware.
if POWER_SEQUENCE
config PWRSEQ_GENERIC
bool "Generic power sequence control"
default y
help
This is the generic power sequence control library, and is
supposed to support common power sequence usage.
endif
And the current user usb core will select POWER_SEQUENCE.
--
Best Regards,
Peter Chen
^ permalink raw reply
* Re: [PATCH v3 12/17] ASoC: simple-card-utils: add asoc_simple_card_try_to_probe_graph_card()
From: kbuild test robot @ 2016-11-11 2:07 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: kbuild-all, Rob Herring, Mark Brown, Linux-ALSA, Liam Girdwood,
Simon, Laurent, Guennadi, Grant Likely, Frank Rowand, Linux-DT,
Linux-Kernel
In-Reply-To: <87eg2ireua.wl%kuninori.morimoto.gx@renesas.com>
[-- Attachment #1: Type: text/plain, Size: 1737 bytes --]
Hi Kuninori,
[auto build test ERROR on asoc/for-next]
[also build test ERROR on v4.9-rc4 next-20161110]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Kuninori-Morimoto/ASoC-add-OF-graph-base-simple-card/20161111-093231
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
config: x86_64-randconfig-x010-201645 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All error/warnings (new ones prefixed by >>):
sound/soc/generic/simple-card-utils.c: In function 'asoc_simple_card_try_to_probe_graph_card':
>> sound/soc/generic/simple-card-utils.c:297:9: error: implicit declaration of function 'of_graph_get_top_port' [-Werror=implicit-function-declaration]
node = of_graph_get_top_port(dev);
^~~~~~~~~~~~~~~~~~~~~
>> sound/soc/generic/simple-card-utils.c:297:7: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
node = of_graph_get_top_port(dev);
^
cc1: some warnings being treated as errors
vim +/of_graph_get_top_port +297 sound/soc/generic/simple-card-utils.c
291 {
292 struct platform_device_info pdevinfo;
293 struct device_node *node;
294 const char *compatible;
295 int ret;
296
> 297 node = of_graph_get_top_port(dev);
298 if (!node || !info)
299 /*
300 * It doesn't have graph base sound DT, or its infomation.
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 23944 bytes --]
^ permalink raw reply
* Re: [PATCH v5 02/23] of: device: Export of_device_{get_modalias, uvent_modalias} to modules
From: Chen-Yu Tsai @ 2016-11-11 3:01 UTC (permalink / raw)
To: Rob Herring
Cc: Chen-Yu Tsai, Peter Chen, Stephen Boyd, Greg KH, Arnd Bergmann,
Neil Armstrong, linux-arm-msm, linux-usb, linux-kernel,
Bjorn Andersson, Peter Chen, linux-arm-kernel, Andy Gross,
devicetree, Felipe Balbi
In-Reply-To: <CAL_Jsq+Bw4XVEJY6V4Hn+D_OmqEcp_nLLrVT0_i+jX_guCqzfA@mail.gmail.com>
On Fri, Nov 11, 2016 at 5:42 AM, Rob Herring <robh@kernel.org> wrote:
> On Sun, Nov 6, 2016 at 7:56 PM, Chen-Yu Tsai <wens@csie.org> wrote:
>> On Mon, Nov 7, 2016 at 9:29 AM, Peter Chen <hzpeterchen@gmail.com> wrote:
>>> On Fri, Nov 04, 2016 at 01:51:34PM -0700, Stephen Boyd wrote:
>>>> Quoting Peter Chen (2016-10-24 18:16:32)
>>>> > On Mon, Oct 24, 2016 at 12:48:24PM -0700, Stephen Boyd wrote:
>>>> > > Quoting Chen-Yu Tsai (2016-10-24 05:19:05)
>>>> > > > Hi,
>>>> > > >
>>>> > > > On Tue, Oct 18, 2016 at 9:56 AM, Stephen Boyd <stephen.boyd@linaro.org> wrote:
>>>> > > > > The ULPI bus can be built as a module, and it will soon be
>>>> > > > > calling these functions when it supports probing devices from DT.
>>>> > > > > Export them so they can be used by the ULPI module.
>>>> > > > >
>>>> > > > > Acked-by: Rob Herring <robh@kernel.org>
>>>> > > > > Cc: <devicetree@vger.kernel.org>
>>>> > > > > Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
>>>> > > > > ---
>>>> > > > > drivers/of/device.c | 2 ++
>>>> > > > > 1 file changed, 2 insertions(+)
>>>> > > > >
>>>> > > > > diff --git a/drivers/of/device.c b/drivers/of/device.c
>>>> > > > > index 8a22a253a830..6719ab35b62e 100644
>>>> > > > > --- a/drivers/of/device.c
>>>> > > > > +++ b/drivers/of/device.c
>>>> > > > > @@ -225,6 +225,7 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len)
>>>> > > > >
>>>> > > > > return tsize;
>>>> > > > > }
>>>> > > > > +EXPORT_SYMBOL_GPL(of_device_get_modalias);
>>>> > > > >
>>>> > > > > int of_device_request_module(struct device *dev)
>>>> > > > > {
>>>> > > > > @@ -290,6 +291,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
>>>> > > > > }
>>>> > > > > mutex_unlock(&of_mutex);
>>>> > > > > }
>>>> > > > > +EXPORT_SYMBOL_GPL(of_device_uevent_modalias);
>>>> > > >
>>>> > > > This is trailing the wrong function.
>>>> > > >
>>>> > >
>>>> > > Good catch. Must have been some bad rebase.
>>>> > >
>>>> > > Peter, can you fix it while applying or should I resend this patch?
>>>> > >
>>>> >
>>>> > But, this is device tree patch. I can only get chipidea part and other
>>>> > USB patches if Greg agrees.
>>>> >
>>>>
>>>> Were you expecting Rob to take the drivers/of/* patches? Sorry I thought
>>>> Rob acked them so they could go through usb with the other changes.
>>>
>>> I am just worried about possible merge error when linus pulls both OF
>>> and USB tree. Greg, is it ok the OF patches through USB tree with OF
>>> maintainer's ack?
>>
>> May I suggest putting the OF patches on an immutable branch so other
>> subsystems can pull them in without pulling in the USB patches? At
>> least I want to use them in the I2C subsystem, and in the sunxi-rsb
>> driver.
>
> Do you have patches using this already. If not, it is starting to get
> a bit late for v4.10.
>
> I can apply this, but then you'll just be pulling in other DT patches.
Not sure what you mean by "using" this...
I have patches which use this to add DT-based modalias entries for
module auto-loading to i2c and sunxi-rsb that I haven't sent.
As far as DT usage goes, we already need this for the axp20x mfd driver.
There are 2 variants, i2c and sunxi-rsb. For the I2C variant a fix was
sent to fix module auto-loading by using the I2C client ID table:
mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading
https://git.kernel.org/cgit/linux/kernel/git/lee/mfd.git/commit/?h=for-mfd-next&id=b7142a19321484bd7681aa547c1d50148c8e2825
But for the sunxi-rsb variant such a fix does not exist, as the bus
does not have a separate ID table. It uses DT exclusively.
Regards
ChenYu
^ permalink raw reply
* Re: [PATCH V3 1/9] PM / OPP: Reword binding supporting multiple regulators per device
From: Viresh Kumar @ 2016-11-11 3:11 UTC (permalink / raw)
To: Stephen Boyd
Cc: Mark Brown, Rafael Wysocki, nm, Viresh Kumar, linaro-kernel,
linux-pm, linux-kernel, Vincent Guittot, robh, d-gerlach,
devicetree
In-Reply-To: <20161110225126.GK16026@codeaurora.org>
On 10-11-16, 14:51, Stephen Boyd wrote:
> On 11/10, Viresh Kumar wrote:
> > On 10-11-16, 16:36, Mark Brown wrote:
> > > On Thu, Nov 10, 2016 at 09:34:40AM +0530, Viresh Kumar wrote:
> > > > On 09-11-16, 14:58, Mark Brown wrote:
> > > > > On Wed, Oct 26, 2016 at 12:02:56PM +0530, Viresh Kumar wrote:
> > >
> > > > > > + Entries for multiple regulators shall be provided in the same field separated
> > > > > > + by angular brackets <>. The OPP binding doesn't provide any provisions to
> > > > > > + relate the values to their power supplies or the order in which the supplies
> > > > > > + need to be configured.
> > >
> > > > > I don't understand how this works. If we have an unordered list of
> > > > > values to set for regulators how will we make sense of them?
> > >
> > > > The platform driver is responsible to identify the order and pass it on to the
> > > > OPP core. And the platform driver needs to have that hard coded.
> > >
> > > That *really* should be in the binding.
> >
> > Okay, how do you suggest doing that? Will a property like supply-names
> > in the OPP table be fine? Like this:
> >
> > @@ -369,13 +378,16 @@ Example 4: Handling multiple regulators
> > compatible = "arm,cortex-a7";
> > ...
> >
> > - cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>;
> > + vcc0-supply = <&cpu_supply0>;
> > + vcc1-supply = <&cpu_supply1>;
> > + vcc2-supply = <&cpu_supply2>;
> > operating-points-v2 = <&cpu0_opp_table>;
> > };
> > };
> >
> > cpu0_opp_table: opp_table0 {
> > compatible = "operating-points-v2";
> > + supply-names = "vcc0", "vcc1", "vcc2";
> > opp-shared;
> >
>
> No. The supply names (and also clock names/index) should be left
> up to the consumer of the OPP table. We don't want to encode any
> sort of details like this between the OPP table and the consumer
> of it in DT because then it seriously couples the OPP table to
> the consumer device. "The binding" in this case that needs to be
> updated is the consumer binding, to indicate that it correlated
> foo-supply and bar-supply to index 0 and 1 of the OPP table
> voltages.
Are you saying that we shall have a property like this then?
diff --git a/Documentation/devicetree/bindings/opp/opp.txt b/Documentation/devicetree/bindings/opp/opp.txt
index ee91cbdd95ee..733946df2fb8 100644
--- a/Documentation/devicetree/bindings/opp/opp.txt
+++ b/Documentation/devicetree/bindings/opp/opp.txt
@@ -389,7 +389,10 @@ Example 4: Handling multiple regulators
compatible = "arm,cortex-a7";
...
- cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>;
+ vcc0-supply = <&cpu_supply0>;
+ vcc1-supply = <&cpu_supply1>;
+ vcc2-supply = <&cpu_supply2>;
+ opp-supply-names = "vcc0", "vcc1", "vcc2";
operating-points-v2 = <&cpu0_opp_table>;
};
};
--
viresh
^ permalink raw reply related
* Re: [PATCH 5/10] dt: bindings: Add bindings for Marvell Xenon SD Host Controller
From: Jisheng Zhang @ 2016-11-11 3:22 UTC (permalink / raw)
To: Ziji Hu, Rob Herring
Cc: Gregory CLEMENT, Ulf Hansson, Adrian Hunter,
linux-mmc-u79uwXL29TY76Z2rM5mHXA, Jason Cooper, Andrew Lunn,
Sebastian Hesselbarth, devicetree-u79uwXL29TY76Z2rM5mHXA,
Thomas Petazzoni,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jack(SH) Zhu,
Jimmy Xu, Nadav Haklai, Ryan Gao, Doug Jones, Shiwu Zhang,
Victor Gu, Wei(SOCP) Liu, Wilson Ding, Xueping Liu, Hilbert
In-Reply-To: <15b06a12-ed69-03a7-ccc7-0c133ce1ac1e-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
Hi Rob, Ziji,
On Thu, 10 Nov 2016 19:44:19 +0800 Ziji Hu wrote:
> Hi Rob,
>
> On 2016/11/10 2:24, Rob Herring wrote:
> > On Mon, Oct 31, 2016 at 12:09:54PM +0100, Gregory CLEMENT wrote:
> >> From: Ziji Hu <huziji-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> >>
> >> Marvell Xenon SDHC can support eMMC/SD/SDIO.
> >> Add Xenon-specific properties.
> >> Also add properties for Xenon PHY setting.
> >>
> >> Signed-off-by: Hu Ziji <huziji-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
> >> Signed-off-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> >> ---
> >> Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt | 161 +++++++-
> >> MAINTAINERS | 1 +-
> >> 2 files changed, 162 insertions(+), 0 deletions(-)
> >> create mode 100644 Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
> >>
> >> diff --git a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
> >> new file mode 100644
> >> index 000000000000..0d2d139494d3
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
> >> @@ -0,0 +1,161 @@
> >> +Marvell's Xenon SDHCI Controller device tree bindings
> >> +This file documents differences between the core mmc properties
> >> +described by mmc.txt and the properties used by the Xenon implementation.
> >> +
> >> +A single Xenon IP can support multiple slots.
> >> +Each slot acts as an independent SDHC. It owns independent resources, such
> >> +as register sets clock and PHY.
> >> +Each slot should have an independent device tree node.
> >> +
> >> +Required Properties:
> >> +- compatible: should be one of the following
> >> + - "marvell,armada-3700-sdhci": For controllers on Armada-3700 SOC.
> >> + Must provide a second register area and marvell,pad-type.
> >> + - "marvell,xenon-sdhci": For controllers on all the SOCs, other than
> >> + Armada-3700.
> >
> > Need SoC specific compatible strings.
> >
>
> Xenon SDHC is a common IP for all Marvell SOCs.
> It is difficult to use a single SOC specific compatible to represent Xenon SDHC.
> There will be so many SOC compatible strings in list if each specific SOC owns a compatible.
> Actually only few SOCs require special properties.
> Any suggestion please?
>
> >> +
> >> +- clocks:
> >> + Array of clocks required for SDHCI.
> >> + Requires at least one for Xenon IP core.
> >> + Some SOCs require additional clock for AXI bus.
> >> +
> >> +- clock-names:
> >> + Array of names corresponding to clocks property.
> >> + The input clock for Xenon IP core should be named as "core".
> >> + The optional AXI clock should be named as "axi".
> >
> > When is AXI clock optional? This should be required for ?? compatible
> > strings.
> >
> It is required on some SOCs.
> I will double check if a suitable compatible string can be determined for those SOCs.
Besides the core clk, berlin SoCs have one AXI clock. Usually, we have two
solutions:
solA: as current patch does, take "marvell,xenon-sdhci" as compatible string
and make the AXI clock property optional. Usually for berlin SoCs, we don't need
special properties.
PS: this solution is also what sdhci-pxav3.c takes
solB: As Rob said, add extra SoC compatible strings, so we'll have
something like:
static const struct of_device_id sdhci_xenon_of_match[] = {
{ .compatible = "marvell,armada-3700-sdhci", },
{ .compatible = "marvell,berlin4ct-sdhci", },
...
{ .compatible = "marvell,berlinxxx-mmc", },
}
then we take care the AXI clk for berlin SoCs in the code.
Which solution do you prefer?
Thanks,
Jisheng
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] phy: rockchip-inno-usb2: correct 480MHz output clock stable time
From: wlf @ 2016-11-11 3:23 UTC (permalink / raw)
To: Heiko Stübner
Cc: Doug Anderson, Kishon Vijay Abraham I,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
open list:ARM/Rockchip SoC...,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Rob Herring,
Frank Wang, 黄涛, Brian Norris, Guenter Roeck,
Matthias Kaehlcke, linux-clk
In-Reply-To: <2283070.Hkeafucara@diego>
Hi Heiko,
在 2016年11月10日 17:21, Heiko Stübner 写道:
> Am Donnerstag, 10. November 2016, 10:54:49 schrieb wlf:
>> Hi Doug,
>>
>> 在 2016年11月10日 04:54, Doug Anderson 写道:
>>> Hi,
>>>
>>> On Mon, Nov 7, 2016 at 5:00 AM, William Wu <wulf-TNX95d0MmH7DzftRWevZcw@public.gmane.org> wrote:
>>>> We found that the system crashed due to 480MHz output clock of
>>>> USB2 PHY was unstable after clock had been enabled by gpu module.
>>>>
>>>> Theoretically, 1 millisecond is a critical value for 480MHz
>>>> output clock stable time, so we try to change the delay time
>>>> to 1.2 millisecond to avoid this issue.
>>>>
>>>> Signed-off-by: William Wu <wulf-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>>>> ---
>>>>
>>>> drivers/phy/phy-rockchip-inno-usb2.c | 2 +-
>>>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/phy/phy-rockchip-inno-usb2.c
>>>> b/drivers/phy/phy-rockchip-inno-usb2.c index ecfd7d1..8f2d2b6 100644
>>>> --- a/drivers/phy/phy-rockchip-inno-usb2.c
>>>> +++ b/drivers/phy/phy-rockchip-inno-usb2.c
>>>> @@ -267,7 +267,7 @@ static int rockchip_usb2phy_clk480m_enable(struct
>>>> clk_hw *hw)>>
>>>> return ret;
>>>>
>>>> /* waitting for the clk become stable */
>>>>
>>>> - mdelay(1);
>>>> + udelay(1200);
>>> Several people who have seen this patch have expressed concern that a
>>> 1.2 ms delay is pretty long for something that's supposed to be
>>> "atomic" like a clk_enable(). Consider that someone might call
>>> clk_enable() while interrupts are disabled and that a 1.2 ms interrupt
>>> latency is not so great.
>>>
>>> It seems like this clock should be moved to be enabled in "prepare"
>>> and the "enable" should be a no-op. This is a functionality change,
>>> but I don't think there are any real users for this clock at the
>>> moment so it should be fine.
>>>
>>> (of course, the 1 ms latency that existed before this patch was still
>>> pretty bad, but ...)
>> Thanks a lot for your suggestion.
>> I agree with you. clk_enable() will call spin_lock_irqsave() to disable
>> interrupt, and we add
>> more than 1ms in clk_enable may cause big latency.
>>
>> And according to clk_prepare() description:
>> In a simple case, clk_prepare can be used instead of clk_enable to
>> ungate a clk if the
>> operation may sleep. One example is a clk which is accessed over I2c.
>>
>> So maybe we can remove the clock to clk_prepare.
>>
>> Hi Heiko, Frank,
>> What do you think of it?
> moving to clk_prepare sounds sensible. That way you can switch from delay to
> sleep functions as well.
Thanks very much.
I will try to update a new patch.
Best regards,
Wulf
>
>
> Heiko
>
>
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 0/3] Add clockevet for timer-nps driver to NPS400 SoC
From: Noam Camus @ 2016-11-11 3:28 UTC (permalink / raw)
To: robh+dt@kernel.org, mark.rutland@arm.com,
daniel.lezcano@linaro.org
Cc: tglx@linutronix.de, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <1478454298-381-1-git-send-email-noamca@mellanox.com>
[-- Attachment #1: Type: text/plain, Size: 3086 bytes --]
Please comment on this series
Noam
________________________________
From: Noam Camus <noamca@mellanox.com>
Sent: Sunday, November 6, 2016 7:44:55 PM
To: robh+dt@kernel.org; mark.rutland@arm.com; daniel.lezcano@linaro.org
Cc: tglx@linutronix.de; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; Noam Camus
Subject: [PATCH v4 0/3] Add clockevet for timer-nps driver to NPS400 SoC
From: Noam Camus <noamca@mellanox.com>
Change log
---
V3 --> V4
Main changes are [Thanks for the review]:
Fix many typos at log [Daniel]
Add handling for bad return values [Daniel and Thomas]
Replace use of internal irqchip pointers with existing IRQ API [Thomas]
Provide interrupt handler (percpu) with dev_id equal to evt [Thomas]
Fix passing *clk by reference to nps_get_timer_clk() [Daniel]
V2 --> V3
Apply Rob Herring comment about backword compatibility
V1 --> V2
Apply Daniel Lezcano comments:
CLOCKSOURCE_OF_DECLARE return value
update hotplug callbacks usage
squash of 2 first commits.
In this version I created new commit to serve as preperation for adding clockevents.
This way the last patch is more readable with clockevent content.
---
In first version of this driver we supported clocksource for the NPS400.
The support for clockevent was taken from Synopsys ARC timer driver.
This was good for working with our simulator of NPS400.
However in NPS400 ASIC the timers behave differently than simulation.
The timers in ASIC are shared between all threads whithin a core
and hence need different driver to support this behaviour.
The idea of this design is that we got 16 HW threads per core
each represented at bimask in a shared register in this core.
So when thread wants that next clockevent expiration will produce
timer interrupt to itself the correspondance bit in this register
should be set.
So theoretically if all 16 bits are set then all HW threads will get
timer interrupt on next expiration of timer 0.
Note that we use Synopsys ARC design naming convention for the timers
where:
timer0 is used for clockevents
timer1 is used for clocksource.
Noam Camus (3):
soc: Support for NPS HW scheduling
clocksource: update "fn" at CLOCKSOURCE_OF_DECLARE() of nps400 timer
clocksource: Add clockevent support to NPS400 driver
.../bindings/timer/ezchip,nps400-timer.txt | 15 --
.../bindings/timer/ezchip,nps400-timer0.txt | 17 ++
.../bindings/timer/ezchip,nps400-timer1.txt | 15 ++
arch/arc/plat-eznps/include/plat/ctop.h | 2 -
drivers/clocksource/timer-nps.c | 264 ++++++++++++++++++--
include/soc/nps/mtm.h | 59 +++++
6 files changed, 335 insertions(+), 37 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt
create mode 100644 Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt
create mode 100644 Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt
create mode 100644 include/soc/nps/mtm.h
[-- Attachment #2: Type: text/html, Size: 5066 bytes --]
^ permalink raw reply
* Re: [PATCH 5/10] dt: bindings: Add bindings for Marvell Xenon SD Host Controller
From: Jisheng Zhang @ 2016-11-11 3:33 UTC (permalink / raw)
To: Ziji Hu, Rob Herring
Cc: Gregory CLEMENT, Ulf Hansson, Adrian Hunter, linux-mmc,
Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, devicetree,
Thomas Petazzoni, linux-arm-kernel, Jack(SH) Zhu, Jimmy Xu,
Nadav Haklai, Ryan Gao, Doug Jones, Shiwu Zhang, Victor Gu,
Wei(SOCP) Liu, Wilson Ding, Xueping Liu, Hilbert
In-Reply-To: <20161111112243.7431625d@xhacker>
On Fri, 11 Nov 2016 11:22:43 +0800 Jisheng Zhang wrote:
> Hi Rob, Ziji,
>
> On Thu, 10 Nov 2016 19:44:19 +0800 Ziji Hu wrote:
>
> > Hi Rob,
> >
> > On 2016/11/10 2:24, Rob Herring wrote:
> > > On Mon, Oct 31, 2016 at 12:09:54PM +0100, Gregory CLEMENT wrote:
> > >> From: Ziji Hu <huziji@marvell.com>
> > >>
> > >> Marvell Xenon SDHC can support eMMC/SD/SDIO.
> > >> Add Xenon-specific properties.
> > >> Also add properties for Xenon PHY setting.
> > >>
> > >> Signed-off-by: Hu Ziji <huziji@marvell.com>
> > >> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> > >> ---
> > >> Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt | 161 +++++++-
> > >> MAINTAINERS | 1 +-
> > >> 2 files changed, 162 insertions(+), 0 deletions(-)
> > >> create mode 100644 Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
> > >>
> > >> diff --git a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
> > >> new file mode 100644
> > >> index 000000000000..0d2d139494d3
> > >> --- /dev/null
> > >> +++ b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
> > >> @@ -0,0 +1,161 @@
> > >> +Marvell's Xenon SDHCI Controller device tree bindings
> > >> +This file documents differences between the core mmc properties
> > >> +described by mmc.txt and the properties used by the Xenon implementation.
> > >> +
> > >> +A single Xenon IP can support multiple slots.
> > >> +Each slot acts as an independent SDHC. It owns independent resources, such
> > >> +as register sets clock and PHY.
> > >> +Each slot should have an independent device tree node.
> > >> +
> > >> +Required Properties:
> > >> +- compatible: should be one of the following
> > >> + - "marvell,armada-3700-sdhci": For controllers on Armada-3700 SOC.
> > >> + Must provide a second register area and marvell,pad-type.
> > >> + - "marvell,xenon-sdhci": For controllers on all the SOCs, other than
> > >> + Armada-3700.
> > >
> > > Need SoC specific compatible strings.
> > >
> >
> > Xenon SDHC is a common IP for all Marvell SOCs.
> > It is difficult to use a single SOC specific compatible to represent Xenon SDHC.
> > There will be so many SOC compatible strings in list if each specific SOC owns a compatible.
> > Actually only few SOCs require special properties.
> > Any suggestion please?
> >
> > >> +
> > >> +- clocks:
> > >> + Array of clocks required for SDHCI.
> > >> + Requires at least one for Xenon IP core.
> > >> + Some SOCs require additional clock for AXI bus.
> > >> +
> > >> +- clock-names:
> > >> + Array of names corresponding to clocks property.
> > >> + The input clock for Xenon IP core should be named as "core".
> > >> + The optional AXI clock should be named as "axi".
> > >
> > > When is AXI clock optional? This should be required for ?? compatible
> > > strings.
> > >
> > It is required on some SOCs.
> > I will double check if a suitable compatible string can be determined for those SOCs.
>
> Besides the core clk, berlin SoCs have one AXI clock. Usually, we have two
> solutions:
>
> solA: as current patch does, take "marvell,xenon-sdhci" as compatible string
> and make the AXI clock property optional. Usually for berlin SoCs, we don't need
> special properties.
Personally, I prefer solA: use the IP name as compatible string. This is IP
specific rather than SoC specific. The HW itself supports two clks
Thanks,
Jisheng
>
> PS: this solution is also what sdhci-pxav3.c takes
>
> solB: As Rob said, add extra SoC compatible strings, so we'll have
> something like:
>
> static const struct of_device_id sdhci_xenon_of_match[] = {
> { .compatible = "marvell,armada-3700-sdhci", },
> { .compatible = "marvell,berlin4ct-sdhci", },
> ...
> { .compatible = "marvell,berlinxxx-mmc", },
> }
>
> then we take care the AXI clk for berlin SoCs in the code.
>
>
> Which solution do you prefer?
>
> Thanks,
> Jisheng
^ permalink raw reply
* Re: [PATCH v5 02/23] of: device: Export of_device_{get_modalias, uvent_modalias} to modules
From: Javier Martinez Canillas @ 2016-11-11 4:25 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: linux-usb, Arnd Bergmann, Neil Armstrong, Greg KH, Stephen Boyd,
linux-kernel, Bjorn Andersson, devicetree, Peter Chen,
linux-arm-kernel, linux-arm-msm, Andy Gross, Peter Chen,
Felipe Balbi
In-Reply-To: <CAGb2v66H1doBOdPPN9kz1vdNYx8gpgkF6s3UhTiXCCp0RZYKwg@mail.gmail.com>
Hello ChenYu
On Fri, Nov 11, 2016 at 12:01 AM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Fri, Nov 11, 2016 at 5:42 AM, Rob Herring <robh@kernel.org> wrote:
[snip]
>>
>> Do you have patches using this already. If not, it is starting to get
>> a bit late for v4.10.
>>
>> I can apply this, but then you'll just be pulling in other DT patches.
>
> Not sure what you mean by "using" this...
>
> I have patches which use this to add DT-based modalias entries for
> module auto-loading to i2c and sunxi-rsb that I haven't sent.
>
Unfortunately the I2C core can't be changed without breaking a lot of
I2C drivers that are relying on the current behavior. I've already
posted a RFC patch [0] for I2C that does this about a year ago and
enumerated the issues that have to be addressed before the change can
be made (and fixed some of the issues mentioned) on this series [1].
Another issue is that an I2C device ID table is a requirement anyways
since I2C drivers expect an i2c_device_id as an argument of their
probe function. Kieran already have patches [2] to change that which
should land soon.
I plan to fix the remaining I2C drivers once his patches are merged
and re-post the RFC patch as a proper one.
> As far as DT usage goes, we already need this for the axp20x mfd driver.
> There are 2 variants, i2c and sunxi-rsb. For the I2C variant a fix was
> sent to fix module auto-loading by using the I2C client ID table:
>
> mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading
> https://git.kernel.org/cgit/linux/kernel/git/lee/mfd.git/commit/?h=for-mfd-next&id=b7142a19321484bd7681aa547c1d50148c8e2825
>
Yes, this is the workaround used by most DT-only I2C drivers. The only
reason that these drivers have an I2C device ID is due the
restrictions imposed by the I2C core.
Best regards,
Javier
^ permalink raw reply
* Re: [PATCH v2 1/3] ARM: dts: imx6qdl-apalis: Do not rely on DDC I2C bus bitbang for HDMI
From: Stefan Agner @ 2016-11-11 4:27 UTC (permalink / raw)
To: Vladimir Zapolskiy, Shawn Guo
Cc: Philipp Zabel, maitysanchayan, marcel.ziswiler, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <7eb3df71-6d1a-006a-cc4c-83ff8df3c42c@mentor.com>
On 2016-11-10 10:29, Vladimir Zapolskiy wrote:
> Hi Stefan, Philipp,
>
> On 11/09/2016 02:50 AM, Stefan Agner wrote:
>> On 2016-11-08 09:33, maitysanchayan@gmail.com wrote:
>>> Hello Shawn,
>>>
>>> On 16-10-22 15:43:04, Vladimir Zapolskiy wrote:
>>>> Hi Shawn,
>>>>
>>>> On 10/22/2016 06:25 AM, Shawn Guo wrote:
>>>>> On Mon, Sep 19, 2016 at 10:41:51AM +0530, Sanchayan Maity wrote:
>>>>>> Remove the use of DDC I2C bus bitbang to support reading of EDID
>>>>>> and rely on support from internal HDMI I2C master controller instead.
>>>>>> As a result remove the device tree property ddc-i2c-bus.
>>>>>>
>>>>>> Signed-off-by: Sanchayan Maity <maitysanchayan@gmail.com>
>>>>>
>>>>> I think that the dw-hdmi i2c support [1] is a prerequisite of this
>>>>> patch. I do not see it lands on v4.9-rc1. Or am I missing something?
>>>>>
>>>>> Shawn
>>>>>
>>>>> [1] https://patchwork.kernel.org/patch/9296883/
>>>>>
>>>>
>>>> I'm adding Philipp to Cc, since he is the last one who tested the change
>>>> and helped me to push the change to the mainline:
>>>>
>>>> https://lists.freedesktop.org/archives/dri-devel/2016-September/118569.html
>>>>
>>>> The problem is that there is no official DW HDMI bridge maintainer, may be
>>>> you can review the change, and if you find it satisfactory push it through
>>>> ARM/iMX tree.
>>>
>>> Shawn, is it okay if that patch goes through your ARM/iMX tree?
>>
>> I don't think it makes sense that the DRM bridge changes go through
>> Shawn's tree. Dave should merge Philipps pull request...
>>
>
> Philipp, do you mind to submit a rebased pull request one more time?
>
You probably saw it, Dave merged it today in his drm-next branch:
https://cgit.freedesktop.org/~airlied/linux/?h=drm-next
I guess with that Shawn can go ahead and merge this patchset for next
too...?
--
Stefan
^ permalink raw reply
* Re: [PATCH v2] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
From: Joel Stanley @ 2016-11-11 4:42 UTC (permalink / raw)
To: Cédric Le Goater
Cc: linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, David Woodhouse,
Brian Norris, Boris Brezillon, Marek Vasut, Richard Weinberger,
Cyrille Pitchen, devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Mark Rutland
In-Reply-To: <1478688149-4554-1-git-send-email-clg-Bxea+6Xhats@public.gmane.org>
On Wed, Nov 9, 2016 at 9:12 PM, Cédric Le Goater <clg-Bxea+6Xhats@public.gmane.org> wrote:
> This driver adds mtd support for spi-nor attached to either or both of
> the Firmware Memory Controller or the SPI Flash Controller (AST2400
> only).
>
> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
> ones found on the AST2400. The differences are on the number of
> supported flash modules and their default mappings in the SoC address
> space.
>
> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
> for the host firmware. All controllers have now the same set of
> registers compatible with the AST2400 FMC controller and the legacy
> 'SMC' controller is fully gone.
>
> Each controller has a memory range on which it maps its flash module
> slaves. Each slave is assigned a memory window for its mapping that
> can be changed at bootime with the Segment Address Register.
>
> Each SPI flash slave can then be accessed in two modes: Command and
> User. When in User mode, accesses to the memory segment of the slaves
> are translated in SPI transfers. When in Command mode, the HW
> generates the SPI commands automatically and the memory segment is
> accessed as if doing a MMIO.
>
> Currently, only the User mode is supported. Command mode needs a
> little more work to check that the memory window on the AHB bus fits
> the module size.
>
> Based on previous work from Milton D. Miller II <miltonm-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
>
> Signed-off-by: Cédric Le Goater <clg-Bxea+6Xhats@public.gmane.org>
> ---
> Tested on:
>
> * OpenPOWER Palmetto (AST2400) with
> FMC controller : n25q256a
> SPI controller : mx25l25635e and n25q512ax3
>
> * Evaluation board (AST2500) with
> FMC controller : w25q256
> SPI controller : w25q256
>
> * OpenPOWER Witherspoon (AST2500) with
> FMC controller : mx25l25635e * 2
> SPI controller : mx66l1g45g
It's also in use on the Zaius and Barreleye OpenBMC systems.
In that respect, I would like to see this merged once it's deemed
ready by the mtd maintainers. We can follow up with the extra features
in future patches.
I've reviewed and tested this as Cedric and Milton have developed it,
so please add:
Reviewed-by: Joel Stanley <joel-U3u1mxZcP9KHXe+LvDLADg@public.gmane.org>
Cheers,
Joel
>
> Changes since v2:
>
> - added a set4b ops to handle difference in the controllers
> - simplified the IO routines
> - prepared for fast read using dummy cycles
>
> Work in progress:
>
> - read optimization using higher SPI clock frequencies
> - command mode to direct reads from AHB
> - DMA support
>
> .../devicetree/bindings/mtd/aspeed-smc.txt | 72 ++
> drivers/mtd/spi-nor/Kconfig | 12 +
> drivers/mtd/spi-nor/Makefile | 1 +
> drivers/mtd/spi-nor/aspeed-smc.c | 783 +++++++++++++++++++++
> 4 files changed, 868 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/aspeed-smc.txt
> create mode 100644 drivers/mtd/spi-nor/aspeed-smc.c
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC 5/5] doc_rst: media: New SDR formats SC16, SC18 & SC20
From: Antti Palosaari @ 2016-11-11 4:54 UTC (permalink / raw)
To: Laurent Pinchart, Ramesh Shanmugasundaram
Cc: robh+dt@kernel.org, mark.rutland@arm.com, mchehab@kernel.org,
hverkuil@xs4all.nl, sakari.ailus@linux.intel.com, Chris Paterson,
geert@linux-m68k.org, linux-media@vger.kernel.org,
devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org
In-Reply-To: <1805711.Tm0TqcXx1h@avalon>
Hello
On 11/10/2016 10:08 AM, Laurent Pinchart wrote:
> Antti, Hans, ping ? Please see below.
>
> On Friday 04 Nov 2016 09:23:29 Ramesh Shanmugasundaram wrote:
>>> On 11/02/2016 10:58 PM, Laurent Pinchart wrote:
>>>> On Wednesday 02 Nov 2016 09:00:00 Ramesh Shanmugasundaram wrote:
>>>>>>> On Wednesday 12 Oct 2016 15:10:29 Ramesh Shanmugasundaram wrote:
>>>>>>>
>>>>>>>> This patch adds documentation for the three new SDR formats
>>>>>>>>
>>>>>>>> V4L2_SDR_FMT_SCU16BE
>>>>>>>> V4L2_SDR_FMT_SCU18BE
>>>>>>>> V4L2_SDR_FMT_SCU20BE
>>>>>
>>>>> [snip]
>>>>>
>>>>>>>> +
>>>>>>>> + - start + 0:
>>>>>>>> +
>>>>>>>> + - I'\ :sub:`0[D13:D6]`
>>>>>>>> +
>>>>>>>> + - I'\ :sub:`0[D5:D0]`
>>>>>>>> +
>>>>>>>> + - .. row 2
>>>>>>>> +
>>>>>>>> + - start + buffer_size/2:
>>>>>>>> +
>>>>>>>> + - Q'\ :sub:`0[D13:D6]`
>>>>>>>> +
>>>>>>>> + - Q'\ :sub:`0[D5:D0]`
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> The format looks planar, does it use one V4L2 plane (as does NV12)
>>>>>>> or two V4L2 planes (as does NV12M) ? Same question for the other
>>>>>>> formats.
>>>>>>
>>>>>> Thank you for bringing up this topic. This is one of the key design
>>>>>> dilemma.
>>>>>>
>>>>>> The I & Q data for these three SDR formats comes from two different
>>>>>> DMA channels and hence two separate pointers -> we could say it is
>>>>>> v4l2 multi- planar. Right now, I am making it look like a single
>>>>>> plane by presenting the data in one single buffer ptr.
>>>>>>
>>>>>> For e.g. multi-planar SC16 format would look something like this
>>>>>>
>>>>>> <------------------------32bits---------------------->
>>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 0
>>>>>> <--I(14 bit data) + 2bit status--16bit padded zeros--> : start0 + 4
>>>>>> ...
>>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 0
>>>>>> <--Q(14 bit data) + 2bit status--16bit padded zeros--> : start1 + 4
>>>>>>
>>>>>> My concerns are
>>>>>>
>>>>>> 1) These formats are not a standard as the video "Image Formats".
>>>>>> These formats are possible when we use DRIF + MAX2175 combination.
>>>>>> If we interface with a different tuner vendor, the above format(s)
>>>>>> MAY/MAY NOT be re-usable. We do not know at this point. This is the
>>>>>> main open item for discussion in the cover letter.
>>>>
>>>> If the formats are really device-specific then they should be
>>>> documented accordingly and not made generic.
>>>>
>>>>>> 2) MPLANE support within V4L2 seems specific to video. Please
>>>>>> correct me if this is wrong interpretation.
>>>>>>
>>>>>> - struct v4l2_format contains v4l2_sdr_format and
>>>>>> v4l2_pix_format_mplane as members of union. Should I create a new
>>>>>> v4l2_sdr_format_mplane? If I have to use v4l2_pix_format_mplane most
>>>>>> of the video specific members would be unused (it would be similar
>>>>>> to using v4l2_pix_format itself instead of v4l2_sdr_format)?
>>>>
>>>> I have no answer to that question as I'm not familiar with SDR. Antti,
>>>> you've added v4l2_sdr_format to the API, what's your opinion ? Hans,
>>>> as you've acked the patch, your input would be appreciated as well.
>>>
>>> If I understood correctly this hardware provides I and Q samples via
>>> different channels and driver now combines those channels as a sequential
>>> IQ sample pairs.
>>
>> The driver combines the two buffer ptrs and present as one single buffer.
>> For a buffer of size 200
>>
>> ptr + 0 : I I I I ... I
>> ptr + 100 : Q Q Q Q ... Q
>>
>>> I have never seen any other than hw which provides IQ IQ IQ IQ ... IQ.
>>
>> There are some modes where this h/w combo can also do IQ IQ IQ pattern.
>> Those modes are not added in the RFC patchset.
>>
>>> This is
>>> I I I I ... I
>>> Q Q Q Q ... Q
>>> I am not very familiar with planars, but it sounds like it is correct
>>> approach. So I think should be added rather than emulate packet
>>> sequential format.
>>
>> My understanding of V4L2 MPLANE constructs is limited to a quick code read
>> only. At this point MPLANE support seems specific to video. SDR is defined
>> as separate format like v4l2_pix_format. Questions would be - should we
>> define new SDR_MPLANE? or merge SDR format with pix format & reuse existing
>> MPLANE with some SDR extensions (if possible)? These seem big design
>> decisions. Any suggestions please?
struct v4l2_format contains union that has own format definition for
video, video mplane and sdr (+many others). Basically on api there is
own definitions for each type, so I think possible sdr mplane should be
similarly own types and definitions.
>> For my use case, MPLANE support does not seem to add significant benefit
>> except it may be syntactically correct. I am doing cyclic DMA with a small
>> set of h/w buffers and copying each stage to one mmapped vmalloc vb2_buffer
>> at two offsets. If we add MPLANE support, it can be two non-contiguous
>> buffer pointers.
If there is no clear idea about need of mplane then that's also fine for me.
And whole mplane concept is new for me. I have never played with any
v4l2 video formats nor mplane video formats.
I would still like to hear what Hans think about adding mplane.
>>
>>>>>> - The above decision (accomodate SDR & MPLANE) needs to be
>>>>>> propagated across the framework. Is this the preferred approach?
>>>>>>
>>>>>> It goes back to point (1). As of today, the change set for this
>>>>>> combo (DRIF+MAX2175) introduces new SDR formats only. Should it add
>>>>>> further SDR+MPLANE support to the framework as well?
>>>>>>
>>>>>> I would appreciate your suggestions on this regard.
>
regards
Antti
--
http://palosaari.fi/
^ permalink raw reply
* Re: [PATCH v16 0/5] Mediatek MT8173 CMDQ support
From: Jassi Brar @ 2016-11-11 5:45 UTC (permalink / raw)
To: Horng-Shyang Liao
Cc: Rob Herring, Matthias Brugger, Daniel Kurtz, Sascha Hauer,
Devicetree List, Linux Kernel Mailing List,
linux-arm-kernel@lists.infradead.org, linux-mediatek,
srv_heupstream, Sascha Hauer, Philipp Zabel, Nicolas Boichat,
CK HU, cawa cheng, Bibby Hsieh, YT Shen, Daoyuan Huang, Damon Chu
In-Reply-To: <1478776558.15447.2.camel@mtksdaap41>
On Thu, Nov 10, 2016 at 4:45 PM, Horng-Shyang Liao <hs.liao@mediatek.com> wrote:
> On Tue, 2016-11-01 at 19:28 +0800, HS Liao wrote:
>> Hi,
>>
>> This is Mediatek MT8173 Command Queue(CMDQ) driver. The CMDQ is used
>> to help write registers with critical time limitation, such as
>> updating display configuration during the vblank. It controls Global
>> Command Engine (GCE) hardware to achieve this requirement.
>>
>> These patches have a build dependency on top of v4.9-rc1.
>>
>> Changes since v15:
>> - separate "suspend and resume" patch from "save energy" patch
>> - don't stop running tasks in cmdq_suspend()
>> (i.e. leave no running tasks guarantee to clients)
>>
>> Best regards,
>> HS Liao
>>
>> HS Liao (5):
>> dt-bindings: soc: Add documentation for the MediaTek GCE unit
>> CMDQ: Mediatek CMDQ driver
>> arm64: dts: mt8173: Add GCE node
>> CMDQ: suspend and resume
>> CMDQ: save energy
>>
>> .../devicetree/bindings/mailbox/mtk-gce.txt | 43 ++
>> arch/arm64/boot/dts/mediatek/mt8173.dtsi | 10 +
>> drivers/mailbox/Kconfig | 10 +
>> drivers/mailbox/Makefile | 2 +
>> drivers/mailbox/mtk-cmdq-mailbox.c | 632 +++++++++++++++++++++
>> drivers/soc/mediatek/Kconfig | 11 +
>> drivers/soc/mediatek/Makefile | 1 +
>> drivers/soc/mediatek/mtk-cmdq-helper.c | 310 ++++++++++
>> include/linux/mailbox/mtk-cmdq-mailbox.h | 67 +++
>> include/linux/soc/mediatek/mtk-cmdq.h | 182 ++++++
>> 10 files changed, 1268 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mailbox/mtk-gce.txt
>> create mode 100644 drivers/mailbox/mtk-cmdq-mailbox.c
>> create mode 100644 drivers/soc/mediatek/mtk-cmdq-helper.c
>> create mode 100644 include/linux/mailbox/mtk-cmdq-mailbox.h
>> create mode 100644 include/linux/soc/mediatek/mtk-cmdq.h
>>
>
>
> Hi Jassi, Matthias,
>
> Sorry to disturb you.
>
No, you don't disturb, but the controller driver and protocol driver,
introduced in the same patch, does :) So does the suspend/resume
support (patch 4&5) added separately as a patch on top. Please
reorganise the patchset.
Thanks.
^ permalink raw reply
* Re: [v17 2/2] drm/bridge: Add I2C based driver for ps8640 bridge
From: Archit Taneja @ 2016-11-11 6:02 UTC (permalink / raw)
To: Enric Balletbo Serra, Jitao Shi, djkurtz-F7+t8E8rja9g9hUCZPvPmw
Cc: David Airlie, Thierry Reding, Matthias Brugger, Mark Rutland,
stonea168-9Onoh4P/yGk, dri-devel, Andy Yan, Ajay Kumar,
Vincent Palatin, cawa cheng, bibby.hsieh-NuS5LvNUpcJWk0Htik3J/w,
CK HU, Russell King,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Sascha Hauer,
Pawel Moll, Ian Campbell, Inki Dae, Rob Herring, ARM/Mediatek
In-Reply-To: <CAFqH_52A4=GubRjPa8X1=STExXFZy2HdoASEGUBYwqGt0BEFcw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Jitao,
I couldn't locate the original mail, so posting on this thread instead.
Some comments below.
On 11/10/2016 10:09 PM, Enric Balletbo Serra wrote:
> Hi Jitao,
>
> 2016-08-27 8:44 GMT+02:00 Jitao Shi <jitao.shi-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>:
>> This patch adds drm_bridge driver for parade DSI to eDP bridge chip.
>>
>> Signed-off-by: Jitao Shi <jitao.shi-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
>> Reviewed-by: Daniel Kurtz <djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> ---
>> Changes since v16:
>> - Disable ps8640 DSI MCS Function.
>> - Rename gpios name more clearly.
>> - Tune the ps8640 power on sequence.
>>
>> Changes since v15:
>> - Drop drm_connector_(un)register calls from parade ps8640.
>> The main DRM driver mtk_drm_drv now calls
>> drm_connector_register_all() after drm_dev_register() in the
>> mtk_drm_bind() function. That function should iterate over all
>> connectors and call drm_connector_register() for each of them.
>> So, remove drm_connector_(un)register calls from parade ps8640.
>>
>> Changes since v14:
>> - update copyright info.
>> - change bridge_to_ps8640 and connector_to_ps8640 to inline function.
>> - fix some coding style.
>> - use sizeof as array counter.
>> - use drm_get_edid when read edid.
>> - add mutex when firmware updating.
>>
>> Changes since v13:
>> - add const on data, ps8640_write_bytes(struct i2c_client *client, const u8 *data, u16 data_len)
>> - fix PAGE2_SW_REST tyro.
>> - move the buf[3] init to entrance of the function.
>>
>> Changes since v12:
>> - fix hw_chip_id build warning
>>
>> Changes since v11:
>> - Remove depends on I2C, add DRM depends
>> - Reuse ps8640_write_bytes() in ps8640_write_byte()
>> - Use timer check for polling like the routines in <linux/iopoll.h>
>> - Fix no drm_connector_unregister/drm_connector_cleanup when ps8640_bridge_attach fail
>> - Check the ps8640 hardware id in ps8640_validate_firmware
>> - Remove fw_version check
>> - Move ps8640_validate_firmware before ps8640_enter_bl
>> - Add ddc_i2c unregister when probe fail and ps8640_remove
>> ---
>> drivers/gpu/drm/bridge/Kconfig | 12 +
>> drivers/gpu/drm/bridge/Makefile | 1 +
>> drivers/gpu/drm/bridge/parade-ps8640.c | 1077 ++++++++++++++++++++++++++++++++
>> 3 files changed, 1090 insertions(+)
>> create mode 100644 drivers/gpu/drm/bridge/parade-ps8640.c
>>
>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
>> index b590e67..c59d043 100644
>> --- a/drivers/gpu/drm/bridge/Kconfig
>> +++ b/drivers/gpu/drm/bridge/Kconfig
>> @@ -50,6 +50,18 @@ config DRM_PARADE_PS8622
>> ---help---
>> Parade eDP-LVDS bridge chip driver.
>>
>> +config DRM_PARADE_PS8640
>> + tristate "Parade PS8640 MIPI DSI to eDP Converter"
>> + depends on DRM
>> + depends on OF
>> + select DRM_KMS_HELPER
>> + select DRM_MIPI_DSI
>> + select DRM_PANEL
>> + ---help---
>> + Choose this option if you have PS8640 for display
>> + The PS8640 is a high-performance and low-power
>> + MIPI DSI to eDP converter
>> +
>> config DRM_SII902X
>> tristate "Silicon Image sii902x RGB/HDMI bridge"
>> depends on OF
>> diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
>> index efdb07e..3360537 100644
>> --- a/drivers/gpu/drm/bridge/Makefile
>> +++ b/drivers/gpu/drm/bridge/Makefile
>> @@ -5,6 +5,7 @@ obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
>> obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
>> obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
>> obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
>> +obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
>> obj-$(CONFIG_DRM_SII902X) += sii902x.o
>> obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
>> obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
>> diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
>> new file mode 100644
>> index 0000000..7d67431
>> --- /dev/null
>> +++ b/drivers/gpu/drm/bridge/parade-ps8640.c
>> @@ -0,0 +1,1077 @@
>> +/*
>> + * Copyright (c) 2016 MediaTek Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/firmware.h>
>> +#include <linux/gpio.h>
Not needed.
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_gpio.h>
The above 2 aren't needed.
>> +#include <linux/of_graph.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <asm/unaligned.h>
>> +#include <drm/drm_panel.h>
>> +
>> +#include <drmP.h>
>> +#include <drm_atomic_helper.h>
>> +#include <drm_crtc_helper.h>
>> +#include <drm_crtc.h>
Not needed.
>> +#include <drm_edid.h>
>> +#include <drm_mipi_dsi.h>
>> +
>> +#define PAGE1_VSTART 0x6b
>> +#define PAGE2_SPI_CFG3 0x82
>> +#define I2C_TO_SPI_RESET 0x20
>> +#define PAGE2_ROMADD_BYTE1 0x8e
>> +#define PAGE2_ROMADD_BYTE2 0x8f
>> +#define PAGE2_SWSPI_WDATA 0x90
>> +#define PAGE2_SWSPI_RDATA 0x91
>> +#define PAGE2_SWSPI_LEN 0x92
>> +#define PAGE2_SWSPI_CTL 0x93
>> +#define TRIGGER_NO_READBACK 0x05
>> +#define TRIGGER_READBACK 0x01
>> +#define PAGE2_SPI_STATUS 0x9e
>> +#define SPI_READY 0x0c
>> +#define PAGE2_GPIO_L 0xa6
>> +#define PAGE2_GPIO_H 0xa7
>> +#define PS_GPIO9 BIT(1)
>> +#define PAGE2_IROM_CTRL 0xb0
>> +#define IROM_ENABLE 0xc0
>> +#define IROM_DISABLE 0x80
>> +#define PAGE2_SW_RESET 0xbc
>> +#define SPI_SW_RESET BIT(7)
>> +#define MPU_SW_RESET BIT(6)
>> +#define PAGE2_ENCTLSPI_WR 0xda
>> +#define PAGE2_I2C_BYPASS 0xea
>> +#define I2C_BYPASS_EN 0xd0
>> +#define PAGE2_MCS_EN 0xf3
>> +#define MCS_EN BIT(0)
>> +#define PAGE3_SET_ADD 0xfe
>> +#define PAGE3_SET_VAL 0xff
>> +#define VDO_CTL_ADD 0x13
>> +#define VDO_DIS 0x18
>> +#define VDO_EN 0x1c
>> +#define PAGE4_REV_L 0xf0
>> +#define PAGE4_REV_H 0xf1
>> +#define PAGE4_CHIP_L 0xf2
>> +#define PAGE4_CHIP_H 0xf3
>> +
>> +/* Firmware */
>> +#define PS_FW_NAME "ps864x_fw.bin"
>> +
>
> About the firmware discussion I think that if you want to maintain the
> upgrade firmware thing you should also include this patch in the
> series.
>
> https://chromium-review.googlesource.com/#/c/317221/
>
> Otherwise, if this is not really needed I think that remove this from
> the driver is the best. Just an opinion, this is something the
> maintainer should decide.
Was there a conclusion on this? As Daniel Kurtz suggested, can we drop
the update firmware stuff for now and try to get the functional part
for 4.10?
>
>> +#define FW_CHIP_ID_OFFSET 0
>> +#define FW_VERSION_OFFSET 2
>> +#define EDID_I2C_ADDR 0x50
>> +
>> +#define WRITE_STATUS_REG_CMD 0x01
>> +#define READ_STATUS_REG_CMD 0x05
>> +#define BUSY BIT(0)
>> +#define CLEAR_ALL_PROTECT 0x00
>> +#define BLK_PROTECT_BITS 0x0c
>> +#define STATUS_REG_PROTECT BIT(7)
>> +#define WRITE_ENABLE_CMD 0x06
>> +#define CHIP_ERASE_CMD 0xc7
>> +#define MAX_DEVS 0x8
>> +
>> +struct ps8640_info {
>> + u8 family_id;
>> + u8 variant_id;
>> + u16 version;
>> +};
>> +
>> +struct ps8640 {
>> + struct drm_connector connector;
>> + struct drm_bridge bridge;
>> + struct edid *edid;
>> + struct mipi_dsi_device dsi;
>> + struct i2c_client *page[MAX_DEVS];
>> + struct i2c_client *ddc_i2c;
>> + struct regulator_bulk_data supplies[2];
>> + struct drm_panel *panel;
>> + struct gpio_desc *gpio_reset;
>> + struct gpio_desc *gpio_power_down;
>> + struct gpio_desc *gpio_mode_sel;
>> + bool enabled;
>> +
>> + /* firmware file info */
>> + struct ps8640_info info;
>> + bool in_fw_update;
>> + /* for firmware update protect */
>> + struct mutex fw_mutex;
>> +};
>> +
>> +static const u8 enc_ctrl_code[6] = { 0xaa, 0x55, 0x50, 0x41, 0x52, 0x44 };
>> +static const u8 hw_chip_id[4] = { 0x00, 0x0a, 0x00, 0x30 };
>> +
>> +static inline struct ps8640 *bridge_to_ps8640(struct drm_bridge *e)
>> +{
>> + return container_of(e, struct ps8640, bridge);
>> +}
>> +
>> +static inline struct ps8640 *connector_to_ps8640(struct drm_connector *e)
>> +{
>> + return container_of(e, struct ps8640, connector);
>> +}
>> +
>> +static int ps8640_read(struct i2c_client *client, u8 reg, u8 *data,
>> + u16 data_len)
>> +{
>> + int ret;
>> + struct i2c_msg msgs[] = {
>> + {
>> + .addr = client->addr,
>> + .flags = 0,
>> + .len = 1,
>> + .buf = ®,
>> + },
>> + {
>> + .addr = client->addr,
>> + .flags = I2C_M_RD,
>> + .len = data_len,
>> + .buf = data,
>> + }
>> + };
>> +
>> + ret = i2c_transfer(client->adapter, msgs, 2);
>> +
>> + if (ret == 2)
>> + return 0;
>> + if (ret < 0)
>> + return ret;
>> + else
>> + return -EIO;
>> +}
>> +
>> +static int ps8640_write_bytes(struct i2c_client *client, const u8 *data,
>> + u16 data_len)
>> +{
>> + int ret;
>> + struct i2c_msg msg;
>> +
>> + msg.addr = client->addr;
>> + msg.flags = 0;
>> + msg.len = data_len;
>> + msg.buf = (u8 *)data;
>> +
>> + ret = i2c_transfer(client->adapter, &msg, 1);
>> + if (ret == 1)
>> + return 0;
>> + if (ret < 0)
>> + return ret;
>> + else
>> + return -EIO;
>> +}
>> +
>> +static int ps8640_write_byte(struct i2c_client *client, u8 reg, u8 data)
>> +{
>> + u8 buf[] = { reg, data };
>> +
>> + return ps8640_write_bytes(client, buf, sizeof(buf));
>> +}
>> +
>> +static void ps8640_get_mcu_fw_version(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[5];
>> + u8 fw_ver[2];
>> +
>> + ps8640_read(client, 0x4, fw_ver, sizeof(fw_ver));
>> + ps_bridge->info.version = (fw_ver[0] << 8) | fw_ver[1];
>> +
>> + DRM_INFO_ONCE("ps8640 rom fw version %d.%d\n", fw_ver[0], fw_ver[1]);
>> +}
>> +
>> +static int ps8640_bridge_unmute(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[3];
>> + u8 vdo_ctrl_buf[3] = { PAGE3_SET_ADD, VDO_CTL_ADD, VDO_EN };
>> +
>> + return ps8640_write_bytes(client, vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
>> +}
>> +
>> +static int ps8640_bridge_mute(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[3];
>> + u8 vdo_ctrl_buf[3] = { PAGE3_SET_ADD, VDO_CTL_ADD, VDO_DIS };
>> +
>> + return ps8640_write_bytes(client, vdo_ctrl_buf, sizeof(vdo_ctrl_buf));
>> +}
>> +
>> +static void ps8640_pre_enable(struct drm_bridge *bridge)
>> +{
>> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> + struct i2c_client *client = ps_bridge->page[2];
>> + struct i2c_client *page1 = ps_bridge->page[1];
It's a bit hard to follow what page[3] or page[5] means without going to the
bottom and reading the dummy devices comment. It would be nice to have some
macros here.
>> + int err;
>> + u8 set_vdo_done, mcs_en, vstart;
>> + ktime_t timeout;
>> +
>> + if (ps_bridge->in_fw_update)
>> + return;
>> +
>> + if (ps_bridge->enabled)
>> + return;
>> +
>> + err = drm_panel_prepare(ps_bridge->panel);
>> + if (err < 0) {
>> + DRM_ERROR("failed to prepare panel: %d\n", err);
>> + return;
>> + }
>> +
>> + err = regulator_bulk_enable(ARRAY_SIZE(ps_bridge->supplies),
>> + ps_bridge->supplies);
>> + if (err < 0) {
>> + DRM_ERROR("cannot enable regulators %d\n", err);
>> + goto err_panel_unprepare;
>> + }
>> +
>> + gpiod_set_value(ps_bridge->gpio_power_down, 1);
>> + gpiod_set_value(ps_bridge->gpio_reset, 0);
>> + usleep_range(2000, 2500);
>> + gpiod_set_value(ps_bridge->gpio_reset, 1);
>> +
>> + /*
>> + * Wait for the ps8640 embed mcu ready
>> + * First wait 200ms and then check the mcu ready flag every 20ms
>> + */
>> + msleep(200);
>> +
>> + timeout = ktime_add_ms(ktime_get(), 200);
>> + for (;;) {
>> + err = ps8640_read(client, PAGE2_GPIO_H, &set_vdo_done, 1);
>> + if (err < 0) {
>> + DRM_ERROR("failed read PAGE2_GPIO_H: %d\n", err);
>> + goto err_regulators_disable;
>> + }
>> + if ((set_vdo_done & PS_GPIO9) == PS_GPIO9)
>> + break;
>> + if (ktime_compare(ktime_get(), timeout) > 0)
>> + break;
>> + msleep(20);
>> + }
>> +
>> + msleep(50);
>> +
>> + ps8640_read(page1, PAGE1_VSTART, &vstart, 1);
>> + DRM_INFO("PS8640 PAGE1.0x6B = 0x%x\n", vstart);
>> +
>> + /**
>> + * The Manufacturer Command Set (MCS) is a device dependent interface
>> + * intended for factory programming of the display module default
>> + * parameters. Once the display module is configured, the MCS shall be
>> + * disabled by the manufacturer. Once disabled, all MCS commands are
>> + * ignored by the display interface.
>> + */
>> + ps8640_read(client, PAGE2_MCS_EN, &mcs_en, 1);
>> + ps8640_write_byte(client, PAGE2_MCS_EN, mcs_en & ~MCS_EN);
>> +
>> + if (ps_bridge->info.version == 0)
>> + ps8640_get_mcu_fw_version(ps_bridge);
>> +
>> + err = ps8640_bridge_unmute(ps_bridge);
>> + if (err)
>> + DRM_ERROR("failed to enable unmutevideo: %d\n", err);
>> + /* Switch access edp panel's edid through i2c */
>> + ps8640_write_byte(client, PAGE2_I2C_BYPASS, I2C_BYPASS_EN);
>> + ps_bridge->enabled = true;
>> +
>> + return;
>> +
>> +err_regulators_disable:
>> + regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> + ps_bridge->supplies);
>> +err_panel_unprepare:
>> + drm_panel_unprepare(ps_bridge->panel);
>> +}
>> +
>> +static void ps8640_enable(struct drm_bridge *bridge)
>> +{
>> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> + int err;
>> +
>> + err = drm_panel_enable(ps_bridge->panel);
>> + if (err < 0)
>> + DRM_ERROR("failed to enable panel: %d\n", err);
>> +}
>> +
>> +static void ps8640_disable(struct drm_bridge *bridge)
>> +{
>> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> + int err;
>> +
>> + err = drm_panel_disable(ps_bridge->panel);
>> + if (err < 0)
>> + DRM_ERROR("failed to disable panel: %d\n", err);
>> +}
>> +
>> +static void ps8640_post_disable(struct drm_bridge *bridge)
>> +{
>> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> + int err;
>> +
>> + if (ps_bridge->in_fw_update)
>> + return;
>> +
>> + if (!ps_bridge->enabled)
>> + return;
>> +
>> + ps_bridge->enabled = false;
>> +
>> + err = ps8640_bridge_mute(ps_bridge);
>> + if (err < 0)
>> + DRM_ERROR("failed to unmutevideo: %d\n", err);
>> +
>> + gpiod_set_value(ps_bridge->gpio_reset, 0);
>> + gpiod_set_value(ps_bridge->gpio_power_down, 0);
>> + err = regulator_bulk_disable(ARRAY_SIZE(ps_bridge->supplies),
>> + ps_bridge->supplies);
>> + if (err < 0)
>> + DRM_ERROR("cannot disable regulators %d\n", err);
>> +
>> + err = drm_panel_unprepare(ps_bridge->panel);
>> + if (err)
>> + DRM_ERROR("failed to unprepare panel: %d\n", err);
>> +}
>> +
>> +static int ps8640_get_modes(struct drm_connector *connector)
>> +{
>> + struct ps8640 *ps_bridge = connector_to_ps8640(connector);
>> + struct edid *edid;
>> + int num_modes = 0;
>> + bool power_off;
>> +
>> + if (ps_bridge->edid)
>> + return drm_add_edid_modes(connector, ps_bridge->edid);
>> +
>> + power_off = !ps_bridge->enabled;
>> + ps8640_pre_enable(&ps_bridge->bridge);
>> +
>> + edid = drm_get_edid(connector, ps_bridge->ddc_i2c->adapter);
See comments related to this in ps8640_probe.
>> + if (!edid)
>> + goto out;
>> +
>> + ps_bridge->edid = edid;
>> + drm_mode_connector_update_edid_property(connector, ps_bridge->edid);
>> + num_modes = drm_add_edid_modes(connector, ps_bridge->edid);
>> +
>> +out:
>> + if (power_off)
>> + ps8640_post_disable(&ps_bridge->bridge);
>> +
>> + return num_modes;
>> +}
>> +
>> +static struct drm_encoder *ps8640_best_encoder(struct drm_connector *connector)
>> +{
>> + struct ps8640 *ps_bridge = connector_to_ps8640(connector);
>> +
>> + return ps_bridge->bridge.encoder;
>> +}
We can drop the above func.
>> +
>> +static const struct drm_connector_helper_funcs ps8640_connector_helper_funcs = {
>> + .get_modes = ps8640_get_modes,
>> + .best_encoder = ps8640_best_encoder,
>> +};
>> +
>> +static enum drm_connector_status ps8640_detect(struct drm_connector *connector,
>> + bool force)
>> +{
>> + return connector_status_connected;
>> +}
>> +
>> +static const struct drm_connector_funcs ps8640_connector_funcs = {
>> + .dpms = drm_atomic_helper_connector_dpms,
>> + .fill_modes = drm_helper_probe_single_connector_modes,
>> + .detect = ps8640_detect,
>> + .reset = drm_atomic_helper_connector_reset,
>> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> +};
>> +
>> +int ps8640_bridge_attach(struct drm_bridge *bridge)
>> +{
>> + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
>> + struct device *dev = &ps_bridge->page[0]->dev;
>> + struct device_node *port, *in_ep;
>> + struct device_node *dsi_node = NULL;
>> + struct mipi_dsi_host *host = NULL;
>> + int ret;
>> +
>> + ret = drm_connector_init(bridge->dev, &ps_bridge->connector,
>> + &ps8640_connector_funcs,
>> + DRM_MODE_CONNECTOR_eDP);
>> +
>> + if (ret) {
>> + DRM_ERROR("Failed to initialize connector with drm: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + drm_connector_helper_add(&ps_bridge->connector,
>> + &ps8640_connector_helper_funcs);
>> +
>> + ps_bridge->connector.dpms = DRM_MODE_DPMS_ON;
>> + drm_mode_connector_attach_encoder(&ps_bridge->connector,
>> + bridge->encoder);
>> +
>> + if (ps_bridge->panel)
>> + drm_panel_attach(ps_bridge->panel, &ps_bridge->connector);
>> +
>> + /* port@0 is ps8640 dsi input port */
>> + port = of_graph_get_port_by_id(dev->of_node, 0);
>> + if (port) {
>> + in_ep = of_get_child_by_name(port, "endpoint");
>> + of_node_put(port);
The above 2 funcs can be done by a single func: of_graph_get_endpoint_by_regs().
>> + if (in_ep) {
>> + dsi_node = of_graph_get_remote_port_parent(in_ep);
>> + of_node_put(in_ep);
>> + }
>> + }
>> + if (dsi_node) {
>> + host = of_find_mipi_dsi_host_by_node(dsi_node);
>> + of_node_put(dsi_node);
>> + if (!host) {
>> + ret = -ENODEV;
>> + goto err;
>> + }
>> + }
>> +
We haven't created a DSI device for this yet. Don't we need to call
mipi_dsi_device_register_full() here?
>> + ps_bridge->dsi.host = host;
The code above proceeds even if we don't find a dsi host. In that
case, the host would be a NULL pointer. We shouldn't call
mipi_dsi_attach() with a NULL host. We should have returned earlier with
an error.
>> + ps_bridge->dsi.mode_flags = MIPI_DSI_MODE_VIDEO |
>> + MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> + ps_bridge->dsi.format = MIPI_DSI_FMT_RGB888;
>> + ps_bridge->dsi.lanes = 4;
>> + ret = mipi_dsi_attach(&ps_bridge->dsi);
>> + if (ret)
>> + goto err;
>> +
>> + return 0;
>> +err:
>> + if (ps_bridge->panel)
>> + drm_panel_detach(ps_bridge->panel);
>> + drm_connector_cleanup(&ps_bridge->connector);
>> + return ret;
>> +}
>> +
>> +static const struct drm_bridge_funcs ps8640_bridge_funcs = {
>> + .attach = ps8640_bridge_attach,
>> + .disable = ps8640_disable,
>> + .post_disable = ps8640_post_disable,
>> + .pre_enable = ps8640_pre_enable,
>> + .enable = ps8640_enable,
>> +};
>> +
>> +/* Firmware Version is returned as Major.Minor */
>> +static ssize_t ps8640_fw_version_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + struct ps8640 *ps_bridge = dev_get_drvdata(dev);
>> + struct ps8640_info *info = &ps_bridge->info;
>> +
>> + return scnprintf(buf, PAGE_SIZE, "%u.%u\n", info->version >> 8,
>> + info->version & 0xff);
>> +}
>> +
>> +/* Hardware Version is returned as FamilyID.VariantID */
>> +static ssize_t ps8640_hw_version_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + struct ps8640 *ps_bridge = dev_get_drvdata(dev);
>> + struct ps8640_info *info = &ps_bridge->info;
>> +
>> + return scnprintf(buf, PAGE_SIZE, "ps%u.%u\n", info->family_id,
>> + info->variant_id);
>> +}
>> +
>> +static int ps8640_spi_send_cmd(struct ps8640 *ps_bridge, u8 *cmd, u8 cmd_len)
>> +{
>> + struct i2c_client *client = ps_bridge->page[2];
>> + u8 i, buf[3] = { PAGE2_SWSPI_LEN, cmd_len - 1, TRIGGER_NO_READBACK };
>> + int ret;
>> +
>> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_ENABLE);
>> + if (ret)
>> + goto err;
>> +
>> + /* write command in write port */
>> + for (i = 0; i < cmd_len; i++) {
>> + ret = ps8640_write_byte(client, PAGE2_SWSPI_WDATA, cmd[i]);
>> + if (ret)
>> + goto err_irom_disable;
>> + }
>> +
>> + ret = ps8640_write_bytes(client, buf, sizeof(buf));
>> + if (ret)
>> + goto err_irom_disable;
>> +
>> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
>> + if (ret)
>> + goto err;
>> +
>> + return 0;
>> +err_irom_disable:
>> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
>> +err:
>> + dev_err(&client->dev, "send command err: %d\n", ret);
>> + return ret;
>> +}
>> +
>> +static int ps8640_wait_spi_ready(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[2];
>> + u8 spi_rdy_st;
>> + ktime_t timeout;
>> +
>> + timeout = ktime_add_ms(ktime_get(), 200);
>> + for (;;) {
>> + ps8640_read(client, PAGE2_SPI_STATUS, &spi_rdy_st, 1);
>> + if ((spi_rdy_st & SPI_READY) != SPI_READY)
>> + break;
>> +
>> + if (ktime_compare(ktime_get(), timeout) > 0) {
>> + dev_err(&client->dev, "wait spi ready timeout\n");
>> + return -EBUSY;
>> + }
>> +
>> + msleep(20);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int ps8640_wait_spi_nobusy(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[2];
>> + u8 spi_status, buf[3] = { PAGE2_SWSPI_LEN, 0, TRIGGER_READBACK };
>> + int ret;
>> + ktime_t timeout;
>> +
>> + timeout = ktime_add_ms(ktime_get(), 500);
>> + for (;;) {
>> + /* 0x05 RDSR; Read-Status-Register */
>> + ret = ps8640_write_byte(client, PAGE2_SWSPI_WDATA,
>> + READ_STATUS_REG_CMD);
>> + if (ret)
>> + goto err_send_cmd_exit;
>> +
>> + ret = ps8640_write_bytes(client, buf, 3);
>> + if (ret)
>> + goto err_send_cmd_exit;
>> +
>> + /* delay for cmd send */
>> + usleep_range(300, 500);
>> + /* wait for SPI ROM until not busy */
>> + ret = ps8640_read(client, PAGE2_SWSPI_RDATA, &spi_status, 1);
>> + if (ret)
>> + goto err_send_cmd_exit;
>> +
>> + if (!(spi_status & BUSY))
>> + break;
>> +
>> + if (ktime_compare(ktime_get(), timeout) > 0) {
>> + dev_err(&client->dev, "wait spi no busy timeout: %d\n",
>> + ret);
>> + return -EBUSY;
>> + }
>> + }
>> +
>> + return 0;
>> +
>> +err_send_cmd_exit:
>> + dev_err(&client->dev, "send command err: %d\n", ret);
>> + return ret;
>> +}
>> +
>> +static int ps8640_wait_rom_idle(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[0];
>> + int ret;
>> +
>> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_ENABLE);
>> + if (ret)
>> + goto exit;
>> +
>> + ret = ps8640_wait_spi_ready(ps_bridge);
>> + if (ret)
>> + goto err_spi;
>> +
>> + ret = ps8640_wait_spi_nobusy(ps_bridge);
>> + if (ret)
>> + goto err_spi;
>> +
>> + ret = ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
>> + if (ret)
>> + goto exit;
>> +
>> + return 0;
>> +
>> +err_spi:
>> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
>> +exit:
>> + dev_err(&client->dev, "wait ps8640 rom idle fail: %d\n", ret);
>> +
>> + return ret;
>> +}
>> +
>> +static int ps8640_spi_dl_mode(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[2];
>> + int ret;
>> +
>> + /* switch ps8640 mode to spi dl mode */
>> + if (ps_bridge->gpio_mode_sel)
>> + gpiod_set_value(ps_bridge->gpio_mode_sel, 0);
>> +
>> + /* reset spi interface */
>> + ret = ps8640_write_byte(client, PAGE2_SW_RESET,
>> + SPI_SW_RESET | MPU_SW_RESET);
>> + if (ret)
>> + goto exit;
>> +
>> + ret = ps8640_write_byte(client, PAGE2_SW_RESET, MPU_SW_RESET);
>> + if (ret)
>> + goto exit;
>> +
>> + return 0;
>> +
>> +exit:
>> + dev_err(&client->dev, "fail reset spi interface: %d\n", ret);
>> +
>> + return ret;
>> +}
>> +
>> +static int ps8640_rom_prepare(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[2];
>> + struct device *dev = &client->dev;
>> + u8 i, cmd[2];
>> + int ret;
>> +
>> + cmd[0] = WRITE_ENABLE_CMD;
>> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 1);
>> + if (ret) {
>> + dev_err(dev, "failed enable-write-status-register: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + cmd[0] = WRITE_STATUS_REG_CMD;
>> + cmd[1] = CLEAR_ALL_PROTECT;
>> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 2);
>> + if (ret) {
>> + dev_err(dev, "fail disable all protection: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /* wait for SPI module ready */
>> + ret = ps8640_wait_rom_idle(ps_bridge);
>> + if (ret) {
>> + dev_err(dev, "fail wait rom idle: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_ENABLE);
>> + for (i = 0; i < ARRAY_SIZE(enc_ctrl_code); i++)
>> + ps8640_write_byte(client, PAGE2_ENCTLSPI_WR, enc_ctrl_code[i]);
>> + ps8640_write_byte(client, PAGE2_IROM_CTRL, IROM_DISABLE);
>> +
>> + /* Enable-Write-Status-Register */
>> + cmd[0] = WRITE_ENABLE_CMD;
>> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 1);
>> + if (ret) {
>> + dev_err(dev, "fail enable-write-status-register: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /* chip erase command */
>> + cmd[0] = CHIP_ERASE_CMD;
>> + ret = ps8640_spi_send_cmd(ps_bridge, cmd, 1);
>> + if (ret) {
>> + dev_err(dev, "fail disable all protection: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = ps8640_wait_rom_idle(ps_bridge);
>> + if (ret) {
>> + dev_err(dev, "fail wait rom idle: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int ps8640_check_chip_id(struct ps8640 *ps_bridge)
>> +{
>> + struct i2c_client *client = ps_bridge->page[4];
>> + u8 buf[4];
>> +
>> + ps8640_read(client, PAGE4_REV_L, buf, 4);
>> + return memcmp(buf, hw_chip_id, sizeof(buf));
>> +}
>> +
>> +static int ps8640_validate_firmware(struct ps8640 *ps_bridge,
>> + const struct firmware *fw)
>> +{
>> + struct i2c_client *client = ps_bridge->page[0];
>> + u16 fw_chip_id;
>> +
>> + /*
>> + * Get the chip_id from the firmware. Make sure that it is the
>> + * right controller to do the firmware and config update.
>> + */
>> + fw_chip_id = get_unaligned_le16(fw->data + FW_CHIP_ID_OFFSET);
>> +
>> + if (fw_chip_id != 0x8640 && ps8640_check_chip_id(ps_bridge) == 0) {
>> + dev_err(&client->dev,
>> + "chip id mismatch: fw 0x%x vs. chip 0x8640\n",
>> + fw_chip_id);
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int ps8640_write_rom(struct ps8640 *ps_bridge, const struct firmware *fw)
>> +{
>> + struct i2c_client *client = ps_bridge->page[0];
>> + struct device *dev = &client->dev;
>> + struct i2c_client *client2 = ps_bridge->page[2];
>> + struct i2c_client *client7 = ps_bridge->page[7];
>> + size_t pos, cpy_len;
>> + u8 buf[257];
>> + int ret;
>> +
>> + ps8640_write_byte(client2, PAGE2_SPI_CFG3, I2C_TO_SPI_RESET);
>> + msleep(100);
>> + ps8640_write_byte(client2, PAGE2_SPI_CFG3, 0x00);
>> +
>> + for (pos = 0; pos < fw->size; pos += cpy_len) {
>> + buf[0] = PAGE2_ROMADD_BYTE1;
>> + buf[1] = pos >> 8;
>> + buf[2] = pos >> 16;
>> + ret = ps8640_write_bytes(client2, buf, 3);
>> + if (ret)
>> + goto error;
>> + cpy_len = fw->size >= 256 + pos ? 256 : fw->size - pos;
>> + buf[0] = 0;
>> + memcpy(buf + 1, fw->data + pos, cpy_len);
>> + ret = ps8640_write_bytes(client7, buf, cpy_len + 1);
>> + if (ret)
>> + goto error;
>> +
>> + dev_dbg(dev, "fw update completed %zu / %zu bytes\n", pos,
>> + fw->size);
>> + }
>> + return 0;
>> +
>> +error:
>> + dev_err(dev, "failed write external flash, %d\n", ret);
>> + return ret;
>> +}
>> +
>> +static int ps8640_spi_normal_mode(struct ps8640 *ps_bridge)
>> +{
>> + u8 cmd[2];
>> + struct i2c_client *client = ps_bridge->page[2];
>> +
>> + /* Enable-Write-Status-Register */
>> + cmd[0] = WRITE_ENABLE_CMD;
>> + ps8640_spi_send_cmd(ps_bridge, cmd, 1);
>> +
>> + /* protect BPL/BP0/BP1 */
>> + cmd[0] = WRITE_STATUS_REG_CMD;
>> + cmd[1] = BLK_PROTECT_BITS | STATUS_REG_PROTECT;
>> + ps8640_spi_send_cmd(ps_bridge, cmd, 2);
>> +
>> + /* wait for SPI rom ready */
>> + ps8640_wait_rom_idle(ps_bridge);
>> +
>> + /* disable PS8640 mapping function */
>> + ps8640_write_byte(client, PAGE2_ENCTLSPI_WR, 0x00);
>> +
>> + if (ps_bridge->gpio_mode_sel)
>> + gpiod_set_value(ps_bridge->gpio_mode_sel, 1);
>> + return 0;
>> +}
>> +
>> +static int ps8640_enter_bl(struct ps8640 *ps_bridge)
>> +{
>> + ps_bridge->in_fw_update = true;
>> + return ps8640_spi_dl_mode(ps_bridge);
>> +}
>> +
>> +static void ps8640_exit_bl(struct ps8640 *ps_bridge, const struct firmware *fw)
>> +{
>> + ps8640_spi_normal_mode(ps_bridge);
>> + ps_bridge->in_fw_update = false;
>> +}
>> +
>> +static int ps8640_load_fw(struct ps8640 *ps_bridge, const struct firmware *fw)
>> +{
>> + struct i2c_client *client = ps_bridge->page[0];
>> + struct device *dev = &client->dev;
>> + int ret;
>> + bool ps8640_status_backup = ps_bridge->enabled;
>> +
>> + ret = ps8640_validate_firmware(ps_bridge, fw);
>> + if (ret)
>> + return ret;
>> +
>> + mutex_lock(&ps_bridge->fw_mutex);
>> + if (!ps_bridge->in_fw_update) {
>> + if (!ps8640_status_backup)
>> + ps8640_pre_enable(&ps_bridge->bridge);
>> +
>> + ret = ps8640_enter_bl(ps_bridge);
>> + if (ret)
>> + goto exit;
>> + }
>> +
>> + ret = ps8640_rom_prepare(ps_bridge);
>> + if (ret)
>> + goto exit;
>> +
>> + ret = ps8640_write_rom(ps_bridge, fw);
>> +
>> +exit:
>> + if (ret)
>> + dev_err(dev, "Failed to load firmware, %d\n", ret);
>> +
>> + ps8640_exit_bl(ps_bridge, fw);
>> + if (!ps8640_status_backup)
>> + ps8640_post_disable(&ps_bridge->bridge);
>> + mutex_unlock(&ps_bridge->fw_mutex);
>> + return ret;
>> +}
>> +
>> +static ssize_t ps8640_update_fw_store(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + struct i2c_client *client = to_i2c_client(dev);
>> + struct ps8640 *ps_bridge = i2c_get_clientdata(client);
>> + const struct firmware *fw;
>> + int error;
>> +
>> + error = request_firmware(&fw, PS_FW_NAME, dev);
>> + if (error) {
>> + dev_err(dev, "Unable to open firmware %s: %d\n",
>> + PS_FW_NAME, error);
>> + return error;
>> + }
>> +
>> + error = ps8640_load_fw(ps_bridge, fw);
>> + if (error)
>> + dev_err(dev, "The firmware update failed(%d)\n", error);
>> + else
>> + dev_info(dev, "The firmware update succeeded\n");
>> +
>> + release_firmware(fw);
>> + return error ? error : count;
>> +}
>> +
>> +static DEVICE_ATTR(fw_version, S_IRUGO, ps8640_fw_version_show, NULL);
>> +static DEVICE_ATTR(hw_version, S_IRUGO, ps8640_hw_version_show, NULL);
>> +static DEVICE_ATTR(update_fw, S_IWUSR, NULL, ps8640_update_fw_store);
>> +
>> +static struct attribute *ps8640_attrs[] = {
>> + &dev_attr_fw_version.attr,
>> + &dev_attr_hw_version.attr,
>> + &dev_attr_update_fw.attr,
>> + NULL
>> +};
>> +
>> +static const struct attribute_group ps8640_attr_group = {
>> + .attrs = ps8640_attrs,
>> +};
>> +
>> +static void ps8640_remove_sysfs_group(void *data)
>> +{
>> + struct ps8640 *ps_bridge = data;
>> +
>> + sysfs_remove_group(&ps_bridge->page[0]->dev.kobj, &ps8640_attr_group);
>> +}
>> +
>> +static int ps8640_probe(struct i2c_client *client,
>> + const struct i2c_device_id *id)
>> +{
>> + struct device *dev = &client->dev;
>> + struct ps8640 *ps_bridge;
>> + struct device_node *np = dev->of_node;
>> + struct device_node *port, *out_ep;
>> + struct device_node *panel_node = NULL;
>> + int ret;
>> + u32 i;
>> +
>> + ps_bridge = devm_kzalloc(dev, sizeof(*ps_bridge), GFP_KERNEL);
>> + if (!ps_bridge)
>> + return -ENOMEM;
>> +
>> + /* port@1 is ps8640 output port */
>> + port = of_graph_get_port_by_id(np, 1);
>> + if (port) {
>> + out_ep = of_get_child_by_name(port, "endpoint");
>> + of_node_put(port);
>> + if (out_ep) {
>> + panel_node = of_graph_get_remote_port_parent(out_ep);
>> + of_node_put(out_ep);
>> + }
>> + }
>> + if (panel_node) {
>> + ps_bridge->panel = of_drm_find_panel(panel_node);
>> + of_node_put(panel_node);
>> + if (!ps_bridge->panel)
>> + return -EPROBE_DEFER;
>> + }
>> +
>> + mutex_init(&ps_bridge->fw_mutex);
>> + ps_bridge->supplies[0].supply = "vdd33";
>> + ps_bridge->supplies[1].supply = "vdd12";
>> + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies),
>> + ps_bridge->supplies);
>> + if (ret) {
>> + dev_info(dev, "failed to get regulators: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ps_bridge->gpio_mode_sel = devm_gpiod_get_optional(&client->dev,
>> + "mode-sel",
>> + GPIOD_OUT_HIGH);
>> + if (IS_ERR(ps_bridge->gpio_mode_sel)) {
>> + ret = PTR_ERR(ps_bridge->gpio_mode_sel);
>> + dev_err(dev, "cannot get mode-sel %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ps_bridge->gpio_power_down = devm_gpiod_get(&client->dev, "sleep",
>> + GPIOD_OUT_LOW);
>> + if (IS_ERR(ps_bridge->gpio_power_down)) {
>> + ret = PTR_ERR(ps_bridge->gpio_power_down);
>> + dev_err(dev, "cannot get sleep: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /*
>> + * Request the reset pin low to avoid the bridge being
>> + * initialized prematurely
>> + */
>> + ps_bridge->gpio_reset = devm_gpiod_get(&client->dev, "reset",
>> + GPIOD_OUT_LOW);
>> + if (IS_ERR(ps_bridge->gpio_reset)) {
>> + ret = PTR_ERR(ps_bridge->gpio_reset);
>> + dev_err(dev, "cannot get reset: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ps_bridge->bridge.funcs = &ps8640_bridge_funcs;
>> + ps_bridge->bridge.of_node = dev->of_node;
>> +
>> + ps_bridge->page[0] = client;
>> + ps_bridge->ddc_i2c = i2c_new_dummy(client->adapter, EDID_I2C_ADDR);
I don't see why we need to create this dummy client. The drm edid helper
drm_get_edid() just needs the i2c adapter to which the client is connected.
It will internally initiate a read form the address EDID_I2C_ADDR.
I guess "drm_get_edid(connector, ps_bridge->page[0]->adapter)" should work.
>> + if (!ps_bridge->ddc_i2c) {
>> + dev_err(dev, "failed ddc_i2c dummy device, address%02x\n",
>> + EDID_I2C_ADDR);
>> + return -EBUSY;
>> + }
>> + /*
>> + * ps8640 uses multiple addresses, use dummy devices for them
>> + * page[0]: for DP control
>> + * page[1]: for VIDEO Bridge
>> + * page[2]: for control top
>> + * page[3]: for DSI Link Control1
>> + * page[4]: for MIPI Phy
>> + * page[5]: for VPLL
>> + * page[6]: for DSI Link Control2
Does this chip support 2 DSI inputs, and we're just exposing one for now?
If so, we should probably revisit the DT bindings, so that port@2 doesn't
need to represent the 2nd DSI link.
Thanks,
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/5] media: i2c: max2175: Add MAX2175 support
From: Antti Palosaari @ 2016-11-11 7:16 UTC (permalink / raw)
To: Ramesh Shanmugasundaram, robh+dt, mark.rutland, mchehab, hverkuil,
sakari.ailus
Cc: chris.paterson2, laurent.pinchart, geert+renesas, linux-media,
devicetree, linux-renesas-soc
In-Reply-To: <1478706284-59134-3-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>
Hello
On 11/09/2016 05:44 PM, Ramesh Shanmugasundaram wrote:
> +static int max2175_set_lo_freq(struct max2175 *ctx, u64 lo_freq)
> +{
> + u64 scaled_lo_freq, scaled_npf, scaled_integer, scaled_fraction;
> + u32 frac_desired, int_desired, lo_mult = 1;
> + const u32 scale_factor = 1000000U;
> + u8 loband_bits = 0, vcodiv_bits = 0;
> + enum max2175_band band;
> + int ret;
> +
> + /* Scale to larger number for precision */
> + scaled_lo_freq = lo_freq * scale_factor * 100;
> + band = max2175_read_bits(ctx, 5, 1, 0);
> +
> + mxm_dbg(ctx, "set_lo_freq: scaled lo_freq %llu lo_freq %llu band %d\n",
> + scaled_lo_freq, lo_freq, band);
> +
> + switch (band) {
> + case MAX2175_BAND_AM:
> + if (max2175_read_bit(ctx, 5, 7) == 0)
> + lo_mult = 16;
else is lo_mult = 1. No idea if it is correct, but sounds very small
output divider for low freq like am band. And on the other-hand local
oscillator output divider, which I expect this to be, is usually 2 or more.
> + break;
> + case MAX2175_BAND_FM:
> + if (lo_freq <= 74700000) {
> + lo_mult = 16;
No meaning as you set it later 8.
> + } else if (lo_freq > 74700000 && lo_freq <= 110000000) {
> + loband_bits = 1;
> + } else {
> + loband_bits = 1;
> + vcodiv_bits = 3;
> + }
> + lo_mult = 8;
> + break;
> + case MAX2175_BAND_VHF:
> + if (lo_freq <= 210000000) {
> + loband_bits = 2;
> + vcodiv_bits = 2;
> + } else {
> + loband_bits = 2;
> + vcodiv_bits = 1;
> + }
> + lo_mult = 4;
> + break;
> + default:
> + loband_bits = 3;
> + vcodiv_bits = 2;
> + lo_mult = 2;
> + break;
> + }
> +
> + if (band == MAX2175_BAND_L)
> + scaled_npf = div_u64(div_u64(scaled_lo_freq, ctx->xtal_freq),
> + lo_mult);
> + else
> + scaled_npf = div_u64(scaled_lo_freq, ctx->xtal_freq) * lo_mult;
> +
> + scaled_npf = div_u64(scaled_npf, 100);
> + scaled_integer = div_u64(scaled_npf, scale_factor) * scale_factor;
> + int_desired = div_u64(scaled_npf, scale_factor);
> + scaled_fraction = scaled_npf - scaled_integer;
> + frac_desired = div_u64(scaled_fraction << 20, scale_factor);
> +
> + /* Check CSM is not busy */
> + ret = max2175_poll_csm_ready(ctx);
> + if (ret)
> + return ret;
> +
> + mxm_dbg(ctx, "loband %u vcodiv %u lo_mult %u scaled_npf %llu\n",
> + loband_bits, vcodiv_bits, lo_mult, scaled_npf);
> + mxm_dbg(ctx, "scaled int %llu frac %llu desired int %u frac %u\n",
> + scaled_integer, scaled_fraction, int_desired, frac_desired);
> +
> + /* Write the calculated values to the appropriate registers */
> + max2175_write(ctx, 1, int_desired);
> + max2175_write_bits(ctx, 2, 3, 0, (frac_desired >> 16) & 0xf);
> + max2175_write(ctx, 3, frac_desired >> 8);
> + max2175_write(ctx, 4, frac_desired);
> + max2175_write_bits(ctx, 5, 3, 2, loband_bits);
> + max2175_write_bits(ctx, 6, 7, 6, vcodiv_bits);
> + return ret;
> +}
That synthesizer config is hard to understand. It seems to be
fractional-N, with configurable N, K and output divider - like a school
book example.
+----------------------------+
v |
Fref +----+ +-------+ +------+
------> | PD | --> | VCO | ------> | /N.F |
+----+ +-------+ +------+
|
|
v
+-------+ Fout
| /Rout | ------>
+-------+
I made following look-up table in order to understand it:
band lo freq band vcodiv div_out
AM < 50000000 0 0 16 // reg 5 bit 7 ?
FM < 74700000 0 0 16
FM < 110000000 1 0 8
FM < 160000000 1 3 8
VHF < 210000000 2 2 4
VHF < 600000000 2 1 4
L <2000000000 3 2 2
"vcodiv" looks unrelated to synth calculation, dunno what it is.
One which makes calculation very complex looking is that it is based of
floating point calculus. On integer mathematics you should replace
fractional part with fractional modulus (usually letter "K" is used for
fractional modulus on PLL calc).
So that ends up something like:
1) select suitable lo output divider from desired output frequency
2) calculate vco frequency
3) convert vco frequency to N and K
* N = Fvco/Fref
* K = Fvco%Fref
4) convert K to control word (looks like << 20)
5) program values
Result should be calculus without scaling.
regards
Antti
--
http://palosaari.fi/
^ permalink raw reply
* Re: [PATCH v5 00/23] Support qcom's HSIC USB and rewrite USB2 HS support
From: Peter Chen @ 2016-11-11 7:40 UTC (permalink / raw)
To: Stephen Boyd
Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA, Felipe Balbi, Heikki Krogerus,
Arnd Bergmann, Neil Armstrong,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Bjorn Andersson,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Peter Chen,
Greg Kroah-Hartman, Andy Gross, Ivan T. Ivanov,
Kishon Vijay Abraham I,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <147682389932.20076.4186408979552866325@sboyd-linaro>
On Tue, Oct 18, 2016 at 01:51:39PM -0700, Stephen Boyd wrote:
> Quoting Peter Chen (2016-10-18 02:31:40)
> > On Mon, Oct 17, 2016 at 06:56:13PM -0700, Stephen Boyd wrote:
> > > I've also sent separate patches for other minor pieces to make this
> > > all work. The full tree can be found here[2], hacks and all to get
> > > things working. I've tested this on the db410c, apq8074 dragonboard,
> > > and ifc6410 with configfs gadgets and otg cables.
> > >
> > > Patches based on v4.8-rc1
>
> Oops should be v4.9-rc1 here.
>
> > >
> > > Changes from v4:
> > > * Picked up Acks from Rob
> > > * Updated HS phy init sequence DT property to restrict it to offsets
> >
> > I remembered that you got all my acks for chipidea patches, right? I did
> > not check for this series.
>
> Sorry I've added in one more patch
>
> usb: chipidea: Emulate OTGSC interrupt enable path
>
> to fix extcon interrupt emulation even further.
>
> >
> > Besides, the patch "gpu: Remove depends on RESET_CONTROLLER when not a
> > provider" [1] still not be accepted, I need this patch to be merged
> > first, then apply your chipidea part, otherwise, there is a building
> > warning.
> >
> > [1] https://patchwork.kernel.org/patch/9322583/
>
> Yes, I'm going to resend that patch now. I hope that David will apply it
> for -rc2.
Stephen, just a mind. I have rebased Greg's usb-next tree (v4.9-rc3 on
it), your GPU fix is still not there.
--
Best Regards,
Peter Chen
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v5 6/8] Documentation: bindings: add compatible specific to legacy SCPI protocol
From: Sudeep Holla @ 2016-11-11 7:48 UTC (permalink / raw)
To: Olof Johansson
Cc: Sudeep Holla, Rob Herring, Neil Armstrong,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <CAOesGMj3TYLkvfGbq6BKqr+9i6mjArjRPuqeAN1-rGO2OhoSyw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 10/11/16 19:03, Olof Johansson wrote:
> On Thu, Nov 10, 2016 at 6:34 AM, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org> wrote:
>>
>>
>> On 10/11/16 14:12, Rob Herring wrote:
>>>
>>> On Thu, Nov 10, 2016 at 4:26 AM, Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org>
>>> wrote:
>>>>
>>>>
>>>>
>>>> On 10/11/16 01:22, Rob Herring wrote:
>>>>>
>>>>>
>>>>> On Wed, Nov 02, 2016 at 10:52:09PM -0600, Sudeep Holla wrote:
>>>>>>
>>>>>>
>>>>>> This patch adds specific compatible to support legacy SCPI protocol.
>>>>>>
>>>>>> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>>>>> Signed-off-by: Sudeep Holla <sudeep.holla-5wv7dgnIgG8@public.gmane.org>
>>>>>> ---
>>>>>> Documentation/devicetree/bindings/arm/arm,scpi.txt | 4 +++-
>>>>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/arm/arm,scpi.txt
>>>>>> b/Documentation/devicetree/bindings/arm/arm,scpi.txt
>>>>>> index d1882c4540d0..ebd03fc93135 100644
>>>>>> --- a/Documentation/devicetree/bindings/arm/arm,scpi.txt
>>>>>> +++ b/Documentation/devicetree/bindings/arm/arm,scpi.txt
>>>>>> @@ -7,7 +7,9 @@ by Linux to initiate various system control and power
>>>>>> operations.
>>>>>>
>>>>>> Required properties:
>>>>>>
>>>>>> -- compatible : should be "arm,scpi"
>>>>>> +- compatible : should be
>>>>>> + * "arm,scpi" : For implementations complying to SCPI v1.0 or
>>>>>> above
>>>>>> + * "arm,legacy-scpi" : For implementations complying pre SCPI
>>>>>> v1.0
>>>>>
>>>>>
>>>>>
>>>>> I'd prefer that we explicitly enumerate the old versions. Are there
>>>>> many?
>>>>>
>>>>
>>>> I understand your concern, but this legacy SCPI protocol was not
>>>> officially released. It was just WIP which vendors picked up from very
>>>> early releases. Since they are not numbered, it's hard to have specific
>>>> compatibles with different versions until v1.0. That's one of the reason
>>>> to retain platform specific compatible so that we can add any quirks
>>>> based on them if needed.
>>>>
>>>> I will probably add these information in the commit log so that it's
>>>> clear why we can't do version based compatible.
>>>
>>>
>>> This is exactly my point. By enumerate, I meant having platform
>>> specific compatibles. Having "arm,legacy-scpi" is pointless because
>>> who knows what version they followed and they may all be different.
>>>
>>
>> OK, but IIUC Olof's concern wanted a generic one along with the platform
>> specific compatible which kind of makes sense as so far we have seen
>> some commonality between Amlogic and Rockchip.
>>
>> E.g. Amlogic follows most of the legacy protocol though it deviates in
>> couple of things which we can handle with platform specific compatible
>> (in the following patch in the series). When another user(Rockchip ?)
>> make use of this legacy protocol, we can start using those platform
>> specific compatible for deviations only.
>>
>> Is that not acceptable ?
>
> If there's no shared legacy feature set, then it's probably less
> useful to have a shared less precise compatible value.
>
There is and will be some shared feature set for sure. At the least the
standard command set will be shared.
> What the main point I was trying to get across was that we shouldn't
> expand the generic binding with per-vendor compatible fields, instead
> we should have those as extensions on the side.
>
Yes I get the point. We will have per-vendor compatibles for handle the
deviations but generic one to handle the shared set.
> I'm also a little apprehensive of using "legacy", it goes in the same
> bucket as "misc". At some point 1.0 will be legacy too, etc.
>
True and I agree, how about "arm,scpi-pre-1.0" instead ?
--
Regards,
Sudeep
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 2/3] Input: ti_am335x_tsc: Add support for ti,charge-delay-ns
From: Mugunthan V N @ 2016-11-11 7:58 UTC (permalink / raw)
To: linux-input-u79uwXL29TY76Z2rM5mHXA
Cc: Dmitry Torokhov, Jonathan Cameron, Rob Herring, Mark Rutland,
Lee Jones, Sekhar Nori, Vignesh R,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N
In-Reply-To: <20161110163515.27598-1-mugunthanvnm-l0cyMroinI0@public.gmane.org>
ti,charge-delay will be deprecated as it represents number of
clock cycles and the DT entries are done in assumption of 3MHz
TSCADC clock, but clock can be set upto 24MHz. So driver add
support for ti,charge-delay-ns and do not drop support for
ti,charge-delay to support old dtbs and it will be assumed that
it is for 3MHz TSCADC clock and will be calculated as per current
clock speed.
Signed-off-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
---
drivers/input/touchscreen/ti_am335x_tsc.c | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 7953381d939a..104b3640f728 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -379,15 +379,30 @@ static int titsc_parse_dt(struct platform_device *pdev,
ts_dev->coordinate_readouts = 5;
}
- err = of_property_read_u32(node, "ti,charge-delay",
+ err = of_property_read_u32(node, "ti,charge-delay-ns",
&ts_dev->charge_delay);
- /*
- * If ti,charge-delay value is not specified, then use
- * CHARGEDLY_OPENDLY as the default value.
- */
- if (err < 0) {
- ts_dev->charge_delay = CHARGEDLY_OPENDLY;
- dev_warn(&pdev->dev, "ti,charge-delay not specified\n");
+ if (err >= 0) {
+ u64 charge_delay = ts_dev->charge_delay;
+
+ charge_delay *= ADC_CLK;
+ do_div(charge_delay, 1E9);
+ ts_dev->charge_delay = (u32)charge_delay;
+ } else {
+ err = of_property_read_u32(node, "ti,charge-delay",
+ &ts_dev->charge_delay);
+ /*
+ * If ti,charge-delay value is not specified, then use
+ * CHARGEDLY_OPENDLY as the default value.
+ */
+ if (err < 0) {
+ ts_dev->charge_delay = CHARGEDLY_OPENDLY;
+ dev_warn(&pdev->dev, "ti,charge-delay not specified\n");
+ }
+ /*
+ * ti,charge-delay is specified with referrence to 3MHz,
+ * so convert it to in referrence to current clock
+ */
+ ts_dev->charge_delay *= ADC_CLK / 3000000;
}
return of_property_read_u32_array(node, "ti,wire-config",
--
2.11.0.rc0.7.gbe5a750
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 3/3] drivers: mfd: ti_am335x_tscadc: increase ADC ref clock to 24MHz
From: Mugunthan V N @ 2016-11-11 7:58 UTC (permalink / raw)
To: linux-input-u79uwXL29TY76Z2rM5mHXA
Cc: Dmitry Torokhov, Jonathan Cameron, Rob Herring, Mark Rutland,
Lee Jones, Sekhar Nori, Vignesh R,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Mugunthan V N
In-Reply-To: <20161110163515.27598-1-mugunthanvnm-l0cyMroinI0@public.gmane.org>
Increase ADC reference clock from 3MHz to 24MHz so that the
sampling rates goes up from 100K samples per second to 800K
samples per second on AM335x and AM437x SoC.
Signed-off-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
---
include/linux/mfd/ti_am335x_tscadc.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h
index b9a53e013bff..f6c449b96ea5 100644
--- a/include/linux/mfd/ti_am335x_tscadc.h
+++ b/include/linux/mfd/ti_am335x_tscadc.h
@@ -137,7 +137,7 @@
#define SEQ_STATUS BIT(5)
#define CHARGE_STEP 0x11
-#define ADC_CLK 3000000
+#define ADC_CLK 24000000
#define TOTAL_STEPS 16
#define TOTAL_CHANNELS 8
#define FIFO1_THRESHOLD 19
--
2.11.0.rc0.7.gbe5a750
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH] ata: xgene: Enable NCQ support for APM X-Gene SATA controller hardware v1.1
From: Rameshwar Sahu @ 2016-11-11 8:06 UTC (permalink / raw)
To: Tejun Heo
Cc: Olof Johansson, linux-scsi-u79uwXL29TY76Z2rM5mHXA,
linux-ide-u79uwXL29TY76Z2rM5mHXA, Devicetree List, linux-arm,
Don Dutile, Jon Masters, patches
In-Reply-To: <20161109164531.GA14630-piEFEHQLUPpN0TnZuCh8vA@public.gmane.org>
Hi Tejun,
On Wed, Nov 9, 2016 at 10:15 PM, Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> Hello,
>
> On Wed, Sep 14, 2016 at 04:15:00PM +0530, Rameshwar Sahu wrote:
>> > @@ -821,8 +823,6 @@ static int xgene_ahci_probe(struct platform_device
>> > *pdev)
>> > dev_warn(&pdev->dev, "%s: Error reading
>> > device info. Assume version1\n",
>> > __func__);
>> > version = XGENE_AHCI_V1;
>> > - } else if (info->valid & ACPI_VALID_CID) {
>> > - version = XGENE_AHCI_V2;
>
> Can you please explain this part a bit? Everything else looks good to
> me.
Here we should not assume XGENE_AHCI_V2 always in case of having valid
_CID in ACPI table.
I need to remove this assumption because V1_1 has also valid _CID for
backward compatibly with v1.
>
> Thanks.
>
> --
> tejun
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox