#define jh7110_clk_debug_init NULL
#endif
+#ifdef CONFIG_PM_SLEEP
+static int jh7110_clk_save_context(struct clk_hw *hw)
+{
+ struct jh7110_clk *clk = jh7110_clk_from(hw);
+ void __iomem *reg = jh7110_clk_reg_addr_get(clk);
+ struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
+
+ if (!clk || !priv)
+ return 0;
+
+ if ((clk->reg_flags == JH7110_CLK_ISP_FLAG) || (clk->reg_flags == JH7110_CLK_VOUT_FLAG))
+ return 0;
+
+ if (clk->idx >= JH7110_CLK_REG_END)
+ return 0;
+
+ spin_lock(&priv->rmw_lock);
+ clk->saved_reg_value = readl_relaxed(reg);
+ spin_unlock(&priv->rmw_lock);
+
+ return 0;
+}
+
+static void jh7110_clk_gate_restore_context(struct clk_hw *hw)
+{
+ struct jh7110_clk *clk = jh7110_clk_from(hw);
+
+ if (!clk)
+ return;
+
+ if ((clk->reg_flags == JH7110_CLK_ISP_FLAG) || (clk->reg_flags == JH7110_CLK_VOUT_FLAG))
+ return;
+
+ if (clk->idx >= JH7110_CLK_REG_END)
+ return;
+
+ jh7110_clk_reg_rmw(clk, JH7110_CLK_ENABLE, clk->saved_reg_value);
+
+ return;
+}
+
+static void jh7110_clk_div_restore_context(struct clk_hw *hw)
+{
+ struct jh7110_clk *clk = jh7110_clk_from(hw);
+
+ if (!clk)
+ return;
+
+ if ((clk->reg_flags == JH7110_CLK_ISP_FLAG) || (clk->reg_flags == JH7110_CLK_VOUT_FLAG))
+ return;
+
+ if (clk->idx >= JH7110_CLK_REG_END)
+ return;
+
+ jh7110_clk_reg_rmw(clk, JH7110_CLK_DIV_MASK, clk->saved_reg_value);
+
+ return;
+}
+
+static void jh7110_clk_mux_restore_context(struct clk_hw *hw)
+{
+ struct jh7110_clk *clk = jh7110_clk_from(hw);
+
+ if (!clk)
+ return;
+
+ if ((clk->reg_flags == JH7110_CLK_ISP_FLAG) || (clk->reg_flags == JH7110_CLK_VOUT_FLAG))
+ return;
+
+ if (clk->idx >= JH7110_CLK_REG_END)
+ return;
+
+ jh7110_clk_reg_rmw(clk, JH7110_CLK_MUX_MASK, clk->saved_reg_value);
+
+ return;
+}
+
+static void jh7110_clk_inv_restore_context(struct clk_hw *hw)
+{
+ struct jh7110_clk *clk = jh7110_clk_from(hw);
+
+ if (!clk)
+ return;
+
+ if ((clk->reg_flags == JH7110_CLK_ISP_FLAG) || (clk->reg_flags == JH7110_CLK_VOUT_FLAG))
+ return;
+
+ if (clk->idx >= JH7110_CLK_REG_END)
+ return;
+
+ jh7110_clk_reg_rmw(clk, JH7110_CLK_INVERT, clk->saved_reg_value);
+
+ return;
+}
+
+static void jh7110_clk_gdiv_restore_context(struct clk_hw *hw)
+{
+ jh7110_clk_div_restore_context(hw);
+ jh7110_clk_gate_restore_context(hw);
+
+ return;
+}
+
+static void jh7110_clk_gmux_restore_context(struct clk_hw *hw)
+{
+ jh7110_clk_mux_restore_context(hw);
+ jh7110_clk_gate_restore_context(hw);
+
+ return;
+}
+
+static void jh7110_clk_mdiv_restore_context(struct clk_hw *hw)
+{
+ jh7110_clk_mux_restore_context(hw);
+ jh7110_clk_div_restore_context(hw);
+
+ return;
+}
+
+static void jh7110_clk_gmd_restore_context(struct clk_hw *hw)
+{
+ jh7110_clk_mux_restore_context(hw);
+ jh7110_clk_div_restore_context(hw);
+ jh7110_clk_gate_restore_context(hw);
+
+ return;
+}
+
+#endif
+
static const struct clk_ops jh7110_clk_gate_ops = {
.enable = jh7110_clk_enable,
.disable = jh7110_clk_disable,
.is_enabled = jh7110_clk_is_enabled,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_gate_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_div_ops = {
.determine_rate = jh7110_clk_determine_rate,
.set_rate = jh7110_clk_set_rate,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_div_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_gdiv_ops = {
.determine_rate = jh7110_clk_determine_rate,
.set_rate = jh7110_clk_set_rate,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_gdiv_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_mux_ops = {
.set_parent = jh7110_clk_set_parent,
.get_parent = jh7110_clk_get_parent,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_mux_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_gmux_ops = {
.set_parent = jh7110_clk_set_parent,
.get_parent = jh7110_clk_get_parent,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_gmux_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_mdiv_ops = {
.set_parent = jh7110_clk_set_parent,
.set_rate = jh7110_clk_set_rate,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_mdiv_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_gmd_ops = {
.set_parent = jh7110_clk_set_parent,
.set_rate = jh7110_clk_set_rate,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_gmd_restore_context,
+#endif
};
static const struct clk_ops jh7110_clk_inv_ops = {
.get_phase = jh7110_clk_get_phase,
.set_phase = jh7110_clk_set_phase,
.debug_init = jh7110_clk_debug_init,
+#ifdef CONFIG_PM_SLEEP
+ .save_context = jh7110_clk_save_context,
+ .restore_context = jh7110_clk_inv_restore_context,
+#endif
};
const struct clk_ops *starfive_jh7110_clk_ops(u32 max)
}
EXPORT_SYMBOL_GPL(starfive_jh7110_clk_ops);
+#ifdef CONFIG_PM_SLEEP
+static int clk_starfive_jh7110_gen_system_suspend(struct device *dev)
+{
+ return clk_save_context();
+}
+
+static int clk_starfive_jh7110_gen_system_resume(struct device *dev)
+{
+ clk_restore_context();
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops clk_starfive_jh7110_gen_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(clk_starfive_jh7110_gen_system_suspend,
+ clk_starfive_jh7110_gen_system_resume)
+};
+
static struct clk_hw *jh7110_clk_get(struct of_phandle_args *clkspec,
void *data)
{
spin_lock_init(&priv->rmw_lock);
priv->dev = &pdev->dev;
+ pm_runtime_enable(priv->dev);
+
#ifdef CONFIG_CLK_STARFIVE_JH7110_PLL
ret = clk_starfive_jh7110_pll_init(pdev, priv->pll_priv);
if (ret)
.driver = {
.name = "clk-starfive-jh7110",
.of_match_table = clk_starfive_jh7110_match,
+ .pm = &clk_starfive_jh7110_gen_pm_ops,
},
};
builtin_platform_driver_probe(clk_starfive_jh7110_driver,
unsigned int idx;
unsigned int max_div;
unsigned int reg_flags;
+ u32 saved_reg_value;
};
struct jh7110_clk_priv {
#include <linux/module.h>
#include <linux/workqueue.h>
-#define LOG_DBG(fmt, arg...) pr_debug("tinker-ft5406: %s: "fmt, __func__, ##arg)
-#define LOG_INFO(fmt, arg...) pr_info("tinker-ft5406: %s: "fmt, __func__, ##arg)
-#define LOG_ERR(fmt, arg...) pr_err("tinker-ft5406: %s: "fmt, __func__, ##arg)
-
#define RETRY_COUNT 10
#define FT_ONE_TCH_LEN 6
#define FT_REG_FW_SUB_MIN_VER 0xB3
#define VALID_TD_STATUS_VAL 10
-#define MAX_TOUCH_POINTS 1
+#define MAX_TOUCH_POINTS 5
#define FT_PRESS 0x7F
#define FT_MAX_ID 0x0F
};
ret = i2c_transfer(client->adapter, msgs, 2);
if (ret < 0)
- LOG_ERR("i2c read error, %d\n", ret);
+ dev_err(&client->dev, "i2c read error, %d\n", ret);
} else {
struct i2c_msg msgs[] = {
{
};
ret = i2c_transfer(client->adapter, msgs, 1);
if (ret < 0)
- LOG_ERR("i2c read error, %d\n", ret);
+ dev_err(&client->dev, "i2c read error, %d\n", ret);
}
return ret;
if (ret < 0)
goto error;
- LOG_INFO("Firmware version = %d.%d.%d\n", fw_ver[0], fw_ver[1], fw_ver[2]);
+ dev_info(&client->dev, "Firmware version = %d.%d.%d\n",
+ fw_ver[0], fw_ver[1], fw_ver[2]);
return 0;
error:
ret = fts_read_reg(ts_data->client, FT_TD_STATUS_REG, &td_status);
if (ret < 0) {
- LOG_ERR("get reg td_status failed, %d\n", ret);
+ dev_err(&ts_data->client->dev,
+ "Get reg td_status failed, %d\n", ret);
return ret;
}
return (int)td_status;
reg_addr = FT_TOUCH_X_H_REG + (i * FT_ONE_TCH_LEN);
ret = fts_i2c_read(ts_data->client, ®_addr, 1, buf, FT_ONE_TCH_LEN-2);
if (ret < 0) {
- LOG_ERR("read touchdata failed.\n");
+ dev_err(&ts_data->client->dev, "Read touchdata failed.\n");
return ret;
}
event->au16_y[i]);
if (!((1 << event->au8_finger_id[i]) & ts_data->known_ids))
- LOG_DBG("Touch id-%d: x = %d, y = %d\n",
+ dev_dbg(&ts_data->client->dev, "Touch id-%d: x = %d, y = %d\n",
event->au8_finger_id[i],
event->au16_x[i],
event->au16_y[i]);
released_ids = ts_data->known_ids & ~modified_ids;
for (i = 0; released_ids && i < MAX_TOUCH_POINTS; i++) {
if (released_ids & (1<<i)) {
- LOG_DBG("Release id-%d, known = %x modified = %x\n",
+ dev_dbg(&ts_data->client->dev, "Release id-%d, known = %x modified = %x\n",
i, ts_data->known_ids, modified_ids);
input_mt_slot(ts_data->input_dev, i);
input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, false);
static int fts_retry_wait(struct tinker_ft5406_data *ts_data)
{
if (ts_data->retry_count < RETRY_COUNT) {
- LOG_INFO("wait and retry, count = %d\n", ts_data->retry_count);
+ dev_info(&ts_data->client->dev,
+ "Wait and retry, count = %d\n", ts_data->retry_count);
ts_data->retry_count++;
msleep(1000);
return 1;
}
- LOG_ERR("attach retry count\n");
+ dev_err(&ts_data->client->dev, "Attach retry count\n");
return 0;
}
if (td_status < 0) {
ret = fts_retry_wait(g_ts_data);
if (ret == 0) {
- LOG_ERR("stop touch polling\n");
+ dev_err(&g_ts_data->client->dev, "Stop touch polling\n");
break;
}
} else if (td_status < VALID_TD_STATUS_VAL + 1 &&
struct input_dev *input_dev;
int ret = 0;
- LOG_INFO("address = 0x%x\n", client->addr);
+ dev_info(&client->dev, "Address = 0x%x\n", client->addr);
g_ts_data = kzalloc(sizeof(struct tinker_ft5406_data), GFP_KERNEL);
if (g_ts_data == NULL) {
- LOG_ERR("no memory for device\n");
+ dev_err(&client->dev, "No memory for device\n");
return -ENOMEM;
}
g_ts_data->screen_height = 480;
g_ts_data->xy_reverse = 1;
- LOG_INFO("width = %d, height = %d, reverse = %d\n",
+ dev_info(&client->dev, "width = %d, height = %d, reverse = %d\n",
g_ts_data->screen_width, g_ts_data->screen_height, g_ts_data->xy_reverse);
ret = fts_check_fw_ver(g_ts_data->client);
if (ret) {
- LOG_ERR("checking touch ic failed\n");
+ dev_err(&client->dev, "Checking touch ic failed\n");
goto check_fw_err;
}
input_dev = input_allocate_device();
if (!input_dev) {
- LOG_ERR("failed to allocate input device\n");
+ dev_err(&client->dev, "Failed to allocate input device\n");
goto input_allocate_failed;
}
input_dev->name = "fts_ts";
ret = input_register_device(input_dev);
if (ret) {
- LOG_ERR("Input device registration failed\n");
+ dev_err(&client->dev, "Input device registration failed\n");
goto input_register_failed;
}
return 0;
-check_fw_failed:
- input_unregister_device(g_ts_data->input_dev);
input_register_failed:
input_free_device(input_dev);
input_allocate_failed:
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
-#define USE_MEDIA_PIPELINE
-
static const struct stfcamss_format_info formats_pix_st7110_wr[] = {
{ MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1,
{ { 1, 1 } }, { { 1, 1 } }, { 16 } },
struct v4l2_subdev *subdev;
int ret;
-#ifdef USE_MEDIA_PIPELINE
- // ret = media_pipeline_start(&vdev->entity, &video->pipe);
ret = media_pipeline_start(&vdev->entity, &video->stfcamss->pipe);
if (ret < 0) {
st_err(ST_VIDEO,
"Failed to media_pipeline_start: %d\n", ret);
return ret;
}
-#endif
+
ret = video_check_format(video);
if (ret < 0)
goto error;
return 0;
error:
-#ifdef USE_MEDIA_PIPELINE
media_pipeline_stop(&vdev->entity);
-#endif
video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
return ret;
}
v4l2_subdev_call(subdev, video, s_stream, 0);
}
-#ifdef USE_MEDIA_PIPELINE
media_pipeline_stop(&vdev->entity);
-#endif
video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
}
file->private_data = vfh;
-#ifdef USE_MEDIA_PIPELINE
- ret = v4l2_pipeline_pm_get(&vdev->entity);
- if (ret < 0) {
- st_err(ST_VIDEO,
- "Failed to power up pipeline: %d\n", ret);
- goto error_pm_use;
+ if (!video->pm_count) {
+ ret = v4l2_pipeline_pm_get(&vdev->entity);
+ if (ret < 0) {
+ st_err(ST_VIDEO,
+ "Failed to power up pipeline: %d\n", ret);
+ goto error_pm_use;
+ }
}
-#else
- struct media_entity *entity;
- struct media_pad *pad;
- struct v4l2_subdev *subdev;
- int i = 0;
-
- entity = &vdev->entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
+ video->pm_count++;
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
-
- ret = v4l2_subdev_call(subdev, core, s_power, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- goto error_power;
- i++;
- }
-#endif
mutex_unlock(&video->lock);
return 0;
-#ifndef USE_MEDIA_PIPELINE
-error_power:
- entity = &vdev->entity;
- while (i--) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
-
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
-
- v4l2_subdev_call(subdev, core, s_power, 0);
- }
-#endif
error_pm_use:
v4l2_fh_release(file);
error_alloc:
static int video_release(struct file *file)
{
struct video_device *vdev = video_devdata(file);
+ struct stfcamss_video *video = video_drvdata(file);
vb2_fop_release(file);
-#ifdef USE_MEDIA_PIPELINE
- v4l2_pipeline_pm_put(&vdev->entity);
-#else
- struct media_entity *entity;
- struct media_pad *pad;
- struct v4l2_subdev *subdev;
- entity = &vdev->entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
-
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
+ video->pm_count--;
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
+ if (!video->pm_count)
+ v4l2_pipeline_pm_put(&vdev->entity);
- v4l2_subdev_call(subdev, core, s_power, 0);
- }
-#endif
file->private_data = NULL;
return 0;
const struct stfcamss_format_info *formats;
unsigned int nformats;
unsigned int is_mp;
+ unsigned int pm_count;
};
int stf_video_register(struct stfcamss_video *video,
spinlock_t output_lock;
const struct vin2_format *formats;
unsigned int nformats;
+#ifdef CONFIG_PM_SLEEP
+ int pm_stream_count;
+ int pm_power_count;
+#endif
};
struct stf_vin2_dev;
struct stfcamss_video *video;
struct video_device *vdev;
int i = 0;
+ int pm_power_count;
+ int pm_stream_count;
for (i = 0; i < VIN_LINE_MAX; i++) {
- if (vin_dev->line[i].stream_count) {
- vin_dev->line[i].stream_count ++;
- video = &vin_dev->line[i].video_out;
- vdev = &vin_dev->line[i].video_out.vdev;
- entity = &vdev->entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
-
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
-
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
-
- v4l2_subdev_call(subdev, video, s_stream, 0);
+ video = &vin_dev->line[i].video_out;
+ vdev = &vin_dev->line[i].video_out.vdev;
+ vin_dev->line[i].pm_power_count = vin_dev->line[i].power_count;
+ vin_dev->line[i].pm_stream_count = vin_dev->line[i].stream_count;
+ pm_power_count = vin_dev->line[i].pm_power_count;
+ pm_stream_count = vin_dev->line[i].pm_stream_count;
+
+ if (pm_stream_count) {
+ while (pm_stream_count--) {
+ entity = &vdev->entity;
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_entity_remote_pad(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ break;
+
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ v4l2_subdev_call(subdev, video, s_stream, 0);
+ }
}
media_pipeline_stop(&vdev->entity);
video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
- v4l2_pipeline_pm_put(&vdev->entity);
}
+
+ if (!pm_power_count)
+ continue;
+
+ v4l2_pipeline_pm_put(&vdev->entity);
}
return pm_runtime_force_suspend(dev);
struct stfcamss_video *video;
struct video_device *vdev;
int i = 0;
+ int pm_power_count;
+ int pm_stream_count;
int ret = 0;
pm_runtime_force_resume(dev);
for (i = 0; i < VIN_LINE_MAX; i++) {
- if (vin_dev->line[i].stream_count) {
- vin_dev->line[i].stream_count--;
- video = &vin_dev->line[i].video_out;
- vdev = &vin_dev->line[i].video_out.vdev;
+ video = &vin_dev->line[i].video_out;
+ vdev = &vin_dev->line[i].video_out.vdev;
+ pm_power_count = vin_dev->line[i].pm_power_count;
+ pm_stream_count = vin_dev->line[i].pm_stream_count;
- ret = v4l2_pipeline_pm_get(&vdev->entity);
- if (ret < 0)
- goto err;
+ if (!pm_power_count)
+ continue;
+ ret = v4l2_pipeline_pm_get(&vdev->entity);
+ if (ret < 0)
+ goto err;
+
+ if (pm_stream_count) {
ret = media_pipeline_start(&vdev->entity, &video->stfcamss->pipe);
if (ret < 0)
goto err_pm_put;
- entity = &vdev->entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
+ while (pm_stream_count--) {
+ entity = &vdev->entity;
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
+ pad = media_entity_remote_pad(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ break;
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(subdev, video, s_stream, 1);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- goto err_pipeline_stop;
+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ goto err_pipeline_stop;
+ }
}
}
}
#define PWMDAC_DUTY_CYCLE_LOW 2
#define PWMDAC_DUTY_CYCLE_HIGH 3
-
-
-
#define PWMDAC_MCLK 4096000
enum pwmdac_lr_change{
PWMDAC_SAMPLE_CNT_511 = 511,
};
-
enum data_shift{
PWMDAC_DATA_LEFT_SHIFT_BIT_0 = 0,
PWMDAC_DATA_LEFT_SHIFT_BIT_1,
struct clk *audio_src;
struct clk *pwmdac_apb;
struct clk *pwmdac_mclk;
+ unsigned int pwmdac_ctrl_data;
};
-
-
-#if IS_ENABLED(CONFIG_SND_STARFIVE_PWMDAC_PCM)
+#if IS_ENABLED(CONFIG_SND_SOC_STARFIVE_PWMDAC_PCM)
void sf_pwmdac_pcm_push_tx(struct sf_pwmdac_dev *dev);
void sf_pwmdac_pcm_pop_rx(struct sf_pwmdac_dev *dev);
int sf_pwmdac_pcm_register(struct platform_device *pdev);
#ifdef CONFIG_PM_SLEEP
static int starfive_pwmdac_system_suspend(struct device *dev)
{
+ struct sf_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
+
+ /* save the register value */
+ pwmdac->pwmdac_ctrl_data = pwmdc_read_reg(pwmdac->pwmdac_base, PWMDAC_CTRL);
return pm_runtime_force_suspend(dev);
}
static int starfive_pwmdac_system_resume(struct device *dev)
{
- return pm_runtime_force_resume(dev);
+ struct sf_pwmdac_dev *pwmdac = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ /* restore the register value */
+ pwmdc_write_reg(pwmdac->pwmdac_base, PWMDAC_CTRL, pwmdac->pwmdac_ctrl_data);
+ return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int spdif_system_suspend(struct device *dev)
{
+ struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
+
+ /* save the register value */
+ regmap_read(spdif->regmap, SPDIF_CTRL, &spdif->reg_spdif_ctrl);
+ regmap_read(spdif->regmap, SPDIF_INT_REG, &spdif->reg_spdif_int);
+ regmap_read(spdif->regmap, SPDIF_FIFO_CTRL, &spdif->reg_spdif_fifo_ctrl);
+
return pm_runtime_force_suspend(dev);
}
static int spdif_system_resume(struct device *dev)
{
- return pm_runtime_force_resume(dev);
+ struct sf_spdif_dev *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ /* restore the register value */
+ regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+ ALLBITMASK, spdif->reg_spdif_ctrl);
+ regmap_update_bits(spdif->regmap, SPDIF_INT_REG,
+ ALLBITMASK, spdif->reg_spdif_int);
+ regmap_update_bits(spdif->regmap, SPDIF_FIFO_CTRL,
+ ALLBITMASK, spdif->reg_spdif_fifo_ctrl);
+
+ return 0;
}
#endif
SET_SYSTEM_SLEEP_PM_OPS(spdif_system_suspend, spdif_system_resume)
};
-
#define SF_PCM_RATE_44100_192000 (SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000 | \
struct clk *mclk;
struct clk *mclk_ext;
struct reset_control *rst_apb;
+ unsigned int reg_spdif_ctrl;
+ unsigned int reg_spdif_int;
+ unsigned int reg_spdif_fifo_ctrl;
struct snd_dmaengine_dai_dma_data dma_data;
};
}
#endif
-
#endif /* __SND_SOC_STARFIVE_SPDIF_H */
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
.rates = SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 |
writel_relaxed(val, dev->tdm_base + reg);
}
+static void sf_tdm_save_context(struct sf_tdm_dev *dev)
+{
+ dev->saved_reg_value[0] = sf_tdm_readl(dev, TDM_PCMGBCR);
+ dev->saved_reg_value[1] = sf_tdm_readl(dev, TDM_PCMTXCR);
+ dev->saved_reg_value[2] = sf_tdm_readl(dev, TDM_PCMRXCR);
+ dev->saved_reg_value[3] = sf_tdm_readl(dev, TDM_PCMDIV);
+}
+
+static void sf_tdm_restore_context(struct sf_tdm_dev *dev)
+{
+ sf_tdm_writel(dev, TDM_PCMGBCR, dev->saved_reg_value[0]);
+ sf_tdm_writel(dev, TDM_PCMTXCR, dev->saved_reg_value[1]);
+ sf_tdm_writel(dev, TDM_PCMRXCR, dev->saved_reg_value[2]);
+ sf_tdm_writel(dev, TDM_PCMDIV, dev->saved_reg_value[3]);
+}
+
static void sf_tdm_start(struct sf_tdm_dev *dev, struct snd_pcm_substream *substream)
{
u32 data;
val &= ~PCMRXCR_RXEN;
sf_tdm_writel(dev, TDM_PCMRXCR, val);
}
+
+ val = sf_tdm_readl(dev, TDM_PCMGBCR);
+ val &= ~PCMGBCR_ENABLE;
+ sf_tdm_writel(dev, TDM_PCMGBCR, val);
}
static int sf_tdm_syncdiv(struct sf_tdm_dev *dev)
clk_disable_unprepare(priv->clk_tdm_ext);
clk_disable_unprepare(priv->clk_tdm_internal);
clk_disable_unprepare(priv->clk_tdm_apb);
+ clk_disable_unprepare(priv->clk_apb0);
clk_disable_unprepare(priv->clk_tdm_ahb);
+ clk_disable_unprepare(priv->clk_ahb0);
clk_disable_unprepare(priv->clk_mclk_inner);
}
return ret;
}
+ ret = clk_prepare_enable(priv->clk_ahb0);
+ if (ret) {
+ dev_err(dev, "Failed to prepare enable clk_ahb0\n");
+ return ret;
+ }
+
ret = clk_prepare_enable(priv->clk_tdm_ahb);
if (ret) {
dev_err(dev, "Failed to prepare enable clk_tdm_ahb\n");
goto dis_mclk_inner;
}
+ ret = clk_prepare_enable(priv->clk_apb0);
+ if (ret) {
+ dev_err(dev, "Failed to prepare enable clk_apb0\n");
+ return ret;
+ }
+
ret = clk_prepare_enable(priv->clk_tdm_apb);
if (ret) {
dev_err(dev, "Failed to prepare enable clk_tdm_apb\n");
goto dis_tdm_ext;
}
+ ret = reset_control_deassert(priv->resets);
+ if (ret) {
+ dev_err(dev, "Failed to deassert tdm resets\n");
+ goto err_reset;
+ }
+
return 0;
+err_reset:
+ clk_disable_unprepare(priv->clk_tdm);
dis_tdm_ext:
clk_disable_unprepare(priv->clk_tdm_ext);
dis_tdm_internal:
}
sf_tdm_config(dev, substream);
+ sf_tdm_save_context(dev);
return 0;
}
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
dev->active++;
+ sf_tdm_restore_context(dev);
sf_tdm_start(dev, substream);
break;
static const struct snd_pcm_hardware jh71xx_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER),
.buffer_bytes_max = 192512,
dev_err(&pdev->dev, "Failed to deassert tdm resets\n");
goto dis_tdm_clk;
}
-
+
return 0;
dis_tdm_clk:
/* data related to DMA transfers b/w tdm and DMAC */
struct snd_dmaengine_dai_dma_data play_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
+ u32 saved_reg_value[4];
};
#endif /* __SND_SOC_STARFIVE_TDM_H */