esoc: Add support for SDX50

Add basic operations to support sdx50 in esoc driver that includes
compatibility, initializations and power control operations (reset,
shutdown, and so on).

Change-Id: Ia53a128b0259d0fc7680bc9452ceaead7b286ca8
Signed-off-by: Satya Durga Srinivasu Prabhala <satyap@codeaurora.org>
tirimbino
Satya Durga Srinivasu Prabhala 8 years ago committed by Raghavendra Rao Ananta
parent 66f220569d
commit 52a313742f
  1. 2
      Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
  2. 131
      drivers/esoc/esoc-mdm-4x.c
  3. 4
      drivers/esoc/esoc-mdm-drv.c
  4. 89
      drivers/esoc/esoc-mdm-pon.c
  5. 3
      drivers/esoc/esoc-mdm.h

@ -6,7 +6,7 @@ to be reset.
Required Properties:
- compatible: The bus devices need to be compatible with
"qcom,ext-mdm9x55"
"qcom,ext-mdm9x55", qcom,ext-sdx50m.
Required named gpio properties:
- qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor

@ -760,6 +760,27 @@ err_state_active:
return retval;
}
static void mdm_release_ipc_gpio(struct mdm_ctrl *mdm)
{
int i;
if (!mdm)
return;
for (i = 0; i < NUM_GPIOS; ++i)
if (gpio_is_valid(MDM_GPIO(mdm, i)))
gpio_free(MDM_GPIO(mdm, i));
}
static void mdm_free_irq(struct mdm_ctrl *mdm)
{
if (!mdm)
return;
free_irq(mdm->errfatal_irq, mdm);
free_irq(mdm->status_irq, mdm);
}
static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
const struct mdm_ops *ops,
struct platform_device *pdev)
@ -851,6 +872,108 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
return 0;
}
static int sdx50m_setup_hw(struct mdm_ctrl *mdm,
const struct mdm_ops *ops,
struct platform_device *pdev)
{
int ret;
struct device_node *node;
struct esoc_clink *esoc;
const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
const struct mdm_pon_ops *pon_ops = ops->pon_ops;
mdm->dev = &pdev->dev;
mdm->pon_ops = pon_ops;
node = pdev->dev.of_node;
esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
if (IS_ERR_OR_NULL(esoc)) {
dev_err(mdm->dev, "cannot allocate esoc device\n");
return PTR_ERR(esoc);
}
esoc->pdev = pdev;
mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0);
if (!mdm->mdm_queue) {
dev_err(mdm->dev, "could not create mdm_queue\n");
return -ENOMEM;
}
mdm->irq_mask = 0;
mdm->ready = false;
ret = mdm_dt_parse_gpios(mdm);
if (ret) {
dev_err(mdm->dev, "Failed to parse DT gpios\n");
goto err_destroy_wrkq;
}
ret = mdm_pon_dt_init(mdm);
if (ret) {
dev_err(mdm->dev, "Failed to parse PON DT gpio\n");
goto err_destroy_wrkq;
}
ret = mdm_pinctrl_init(mdm);
if (ret) {
dev_err(mdm->dev, "Failed to init pinctrl\n");
goto err_destroy_wrkq;
}
ret = mdm_pon_setup(mdm);
if (ret) {
dev_err(mdm->dev, "Failed to setup PON\n");
goto err_destroy_wrkq;
}
ret = mdm_configure_ipc(mdm, pdev);
if (ret) {
dev_err(mdm->dev, "Failed to configure the ipc\n");
goto err_release_ipc;
}
esoc->name = SDX50M_LABEL;
mdm->dual_interface = of_property_read_bool(node,
"qcom,mdm-dual-link");
esoc->link_name = SDX50M_PCIE;
ret = of_property_read_string(node, "qcom,mdm-link-info",
&esoc->link_info);
if (ret)
dev_info(mdm->dev, "esoc link info missing\n");
esoc->clink_ops = clink_ops;
esoc->parent = mdm->dev;
esoc->owner = THIS_MODULE;
esoc->np = pdev->dev.of_node;
set_esoc_clink_data(esoc, mdm);
ret = esoc_clink_register(esoc);
if (ret) {
dev_err(mdm->dev, "esoc registration failed\n");
goto err_free_irq;
}
dev_dbg(mdm->dev, "esoc registration done\n");
init_completion(&mdm->debug_done);
INIT_WORK(&mdm->mdm_status_work, mdm_status_fn);
INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason);
INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check);
mdm->get_restart_reason = false;
mdm->debug_fail = false;
mdm->esoc = esoc;
mdm->init = 0;
return 0;
err_free_irq:
mdm_free_irq(mdm);
err_release_ipc:
mdm_release_ipc_gpio(mdm);
err_destroy_wrkq:
destroy_workqueue(mdm->mdm_queue);
return ret;
}
static struct esoc_clink_ops mdm_cops = {
.cmd_exe = mdm_cmd_exe,
.get_status = mdm_get_status,
@ -864,9 +987,17 @@ static struct mdm_ops mdm9x55_ops = {
.pon_ops = &mdm9x55_pon_ops,
};
static struct mdm_ops sdx50m_ops = {
.clink_ops = &mdm_cops,
.config_hw = sdx50m_setup_hw,
.pon_ops = &sdx50m_pon_ops,
};
static const struct of_device_id mdm_dt_match[] = {
{ .compatible = "qcom,ext-mdm9x55",
.data = &mdm9x55_ops, },
{ .compatible = "qcom,ext-sdx50m",
.data = &sdx50m_ops, },
{},
};
MODULE_DEVICE_TABLE(of, mdm_dt_match);

@ -301,6 +301,10 @@ static struct esoc_compat compat_table[] = {
.name = "MDM9x55",
.data = NULL,
},
{
.name = "SDX50M",
.data = NULL,
},
};
static struct esoc_drv esoc_ssr_drv = {

@ -41,6 +41,34 @@ static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
return 0;
}
/* This function can be called from atomic context. */
static int sdx50m_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
{
int soft_reset_direction_assert = 0,
soft_reset_direction_de_assert = 1;
if (mdm->soft_reset_inverted) {
soft_reset_direction_assert = 1;
soft_reset_direction_de_assert = 0;
}
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
soft_reset_direction_assert);
/*
* Allow PS hold assert to be detected
*/
if (!atomic)
usleep_range(203000, 300000);
else
/*
* The flow falls through this path as a part of the
* panic handler, which has to executed atomically.
*/
mdelay(203);
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
soft_reset_direction_de_assert);
return 0;
}
static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
{
int i;
@ -101,6 +129,26 @@ static int mdm9x55_power_down(struct mdm_ctrl *mdm)
return 0;
}
static int sdx50m_power_down(struct mdm_ctrl *mdm)
{
struct device *dev = mdm->dev;
int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
/* Assert the soft reset line whether mdm2ap_status went low or not */
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
soft_reset_direction);
dev_dbg(dev, "Doing a hard reset\n");
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
soft_reset_direction);
/*
* Currently, there is a debounce timer on the charm PMIC. It is
* necessary to hold the PMIC RESET low for 406ms
* for the reset to fully take place. Sleep here to ensure the
* reset has occurred before the function exits.
*/
msleep(406);
return 0;
}
static void mdm9x55_cold_reset(struct mdm_ctrl *mdm)
{
dev_dbg(mdm->dev, "Triggering mdm cold reset");
@ -117,6 +165,22 @@ static void mdm9x55_cold_reset(struct mdm_ctrl *mdm)
!mdm->soft_reset_inverted);
}
static void sdx50m_cold_reset(struct mdm_ctrl *mdm)
{
dev_dbg(mdm->dev, "Triggering mdm cold reset");
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
!!mdm->soft_reset_inverted);
/*
* The function is executed as a part of the atomic reboot handler.
* Hence, go with a busy loop instead of sleep.
*/
mdelay(334);
gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
!mdm->soft_reset_inverted);
}
static int mdm9x55_pon_dt_init(struct mdm_ctrl *mdm)
{
int val;
@ -140,6 +204,23 @@ static int mdm9x55_pon_dt_init(struct mdm_ctrl *mdm)
return -EIO;
}
static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
{
int val;
struct device_node *node = mdm->dev->of_node;
enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio",
0, &flags);
if (val >= 0) {
MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val;
if (flags & OF_GPIO_ACTIVE_LOW)
mdm->soft_reset_inverted = 1;
return 0;
} else
return -EIO;
}
static int mdm4x_pon_setup(struct mdm_ctrl *mdm)
{
struct device *dev = mdm->dev;
@ -163,3 +244,11 @@ struct mdm_pon_ops mdm9x55_pon_ops = {
.setup = mdm4x_pon_setup,
};
struct mdm_pon_ops sdx50m_pon_ops = {
.pon = mdm4x_do_first_power_on,
.soft_reset = sdx50m_toggle_soft_reset,
.poff_force = sdx50m_power_down,
.cold_reset = sdx50m_cold_reset,
.dt_init = mdm4x_pon_dt_init,
.setup = mdm4x_pon_setup,
};

@ -29,6 +29,8 @@
#define MDM_GPIO(mdm, i) (mdm->gpios[i])
#define MDM9x55_LABEL "MDM9x55"
#define MDM9x55_PCIE "PCIe"
#define SDX50M_LABEL "SDX50M"
#define SDX50M_PCIE "PCIe"
#define MDM2AP_STATUS_TIMEOUT_MS 120000L
#define MDM_MODEM_TIMEOUT 3000
#define DEF_RAMDUMP_TIMEOUT 120000
@ -146,4 +148,5 @@ static inline int mdm_pon_setup(struct mdm_ctrl *mdm)
}
extern struct mdm_pon_ops mdm9x55_pon_ops;
extern struct mdm_pon_ops sdx50m_pon_ops;
#endif

Loading…
Cancel
Save